Tornado AsyncHTTPClient performance degradationTornado AsyncHTTPClient fetch callback: Extra parameters?loop using AsyncHTTPClient (Tornado, Python)Tornado asynchttpclient results in NoneSocks proxy in tornado AsyncHttpClientPython tornado AsyncHTTPClient flukeTornado AsyncHTTPClient() chunksAsyncHTTPClient blocking my Tornado IOLoopDownloading large files with tornado AsyncHTTPClient streaming_callback failsPython tornado AsyncHTTPClient 599Wait for requests done by AsyncHTTPClient in Tornado

Is conquering your neighbors to fight a greater enemy a valid strategy?

Why do airports remove/realign runways?

Category-theoretic treatment of diffs, patches and merging?

Why did RFK loathe LBJ?

The flying colours

Is it acceptable that I plot a time-series figure with years increasing from right to left?

How to say "is going" in Russian in "this game is going to perish"

Possibility to correct pitch from digital versions of records with the hole not centered

Why does the Misal rico de Cisneros uses the word "Qiſſa", and what is it supposed to mean? Why not "Miſſa" (Missa)?

Taking my Ph.D. advisor out for dinner after graduation

Floating Pumice Road. Slab Size

What are the consequences for a developed nation to not accept any refugee?

How can I use my cell phone's light as a reading light?

Gory anime with pink haired girl escaping an asylum

Taking advantage when HR forgets to communicate the rules

Why does "mi piace" mean "I like" instead of "he/she/it likes me"?

Why do Martians have to wear space helmets?

How was the website able to tell my credit card was wrong before it processed it?

Troubling glyphs

What is the meaning of "prairie-dog" in this sentence?

Why no parachutes in the Orion AA2 abort test?

When moving a unique_ptr into a lambda, why is it not possible to call reset?

What does "spinning upon the shoals" mean?

As a supervisor, what feedback would you expect from a PhD who quits?



Tornado AsyncHTTPClient performance degradation


Tornado AsyncHTTPClient fetch callback: Extra parameters?loop using AsyncHTTPClient (Tornado, Python)Tornado asynchttpclient results in NoneSocks proxy in tornado AsyncHttpClientPython tornado AsyncHTTPClient flukeTornado AsyncHTTPClient() chunksAsyncHTTPClient blocking my Tornado IOLoopDownloading large files with tornado AsyncHTTPClient streaming_callback failsPython tornado AsyncHTTPClient 599Wait for requests done by AsyncHTTPClient in Tornado






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








0















Setup: Python 2.7.15, Tornado 5.1



I have a web-server machine that handles ~40 /recommend requests per second.
The average response time is 25ms, but there's a big divergence (some requests can take more than 500ms).



Each request generates between 1-8 Elasticsearch queries (HTTP requests) internally.
Each Elasticsearch query can take between 1-150ms.



The Elasticsearch requests are handled synchronously via elasticsearch-dsl library.



The goal is to reduce the i/o waiting time (queries to Elasticsearch) and handle more requests per second so I can reduce the number of machines.
One thing is unacceptable - I don't want to increase the average handle time (25ms).



I found some tornado-elasticsearch implementations on the web, but since I need to use only one endpoint to Elasticsearch (/_search) I am trying to do that alone.



Below there's a degenerated implementation of my web-server. With the same load (~40 request per second) the average request response time increased to 200ms!



Digging in, I see that the internal async handle time (queries to Elasticsearch) is not stable and the time takes to each fetch call might be different, and the total average (in ab load test) is high.



I'm using ab to simulate the load and measure it internally by printing the current fetch handle time, average fetch handle time and maximum handle time.
When doing one request at a time (concurrency 1):
ab -p es-query-rcom.txt -T application/json -n 1000 -c 1 -k 'http://localhost:5002/recommend'



my prints looks like: [avg req_time: 3, dur: 3] [current req_time: 2, dur: 3] [max req_time: 125, dur: 125] reqs: 8000



But when I try to increase the concurrency (up to 8): ab -p es-query-rcom.txt -T application/json -n 1000 -c 8 -k 'http://localhost:5002/recommend'



now my prints looks like: [avg req_time: 6, dur: 13] [current req_time: 4, dur: 4] [max req_time: 73, dur: 84] reqs: 8000



The average req is now x2 slower (or x4 by my measurements)!
What do I miss here? why do I see this degradation?



web_server.py:



import tornado
from tornado.httpclient import AsyncHTTPClient
from tornado.options import define, options
from tornado.httpserver import HTTPServer
from web_handler import WebHandler

SERVICE_NAME = 'web_server'
NUM_OF_PROCESSES = 1


class Statistics(object):
def __init__(self):
self.total_requests = 0
self.total_requests_time = 0
self.total_duration = 0
self.max_time = 0
self.max_duration = 0


class RcomService(object):
def __init__(self):
print 'initializing RcomService...'
AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient", max_clients=3)
self.stats = Statistics()

def start(self, port):
define("port", default=port, type=int)
db = self.get_db(self.stats)
routes = self.generate_routes(db)
app = tornado.web.Application(routes)
http_server = HTTPServer(app, xheaders=True)
http_server.bind(options.port)
http_server.start(NUM_OF_PROCESSES)
tornado.ioloop.IOLoop.current().start()

@staticmethod
def generate_routes(db):
return [
(r"/recommend", WebHandler, dict(db=db))
]

@staticmethod
def get_db(stats):
return
'stats': stats



def main():
port = 5002
print('starting %s on port %s', SERVICE_NAME, port)

rcom_service = RcomService()
rcom_service.start(port)


if __name__ == '__main__':
main()


web_handler.py:



import time
import ujson
from tornado import gen
from tornado.gen import coroutine
from tornado.httpclient import AsyncHTTPClient
from tornado.web import RequestHandler


class WebHandler(RequestHandler):
def initialize(self, db):
self.stats = db['stats']

@coroutine
def post(self, *args, **kwargs):
result = yield self.wrapper_innear_loop([, , , , , , , ]) # dummy queries (empty)
self.write(
'res': result
)

@coroutine
def wrapper_innear_loop(self, queries):
result = []
for q in queries: # queries are performed serially
res = yield self.async_fetch_gen(q)
result.append(res)
raise gen.Return(result)

@coroutine
def async_fetch_gen(self, query):
url = 'http://localhost:9200/my_index/_search'

headers =
'Content-Type': 'application/json',
'Connection': 'keep-alive'


http_client = AsyncHTTPClient()
start_time = int(round(time.time() * 1000))
response = yield http_client.fetch(url, method='POST', body=ujson.dumps(query), headers=headers)
end_time = int(round(time.time() * 1000))
duration = end_time - start_time
body = ujson.loads(response.body)
request_time = int(round(response.request_time * 1000))
self.stats.total_requests += 1
self.stats.total_requests_time += request_time
self.stats.total_duration += duration
if self.stats.max_time < request_time:
self.stats.max_time = request_time
if self.stats.max_duration < duration:
self.stats.max_duration = duration
duration_avg = self.stats.total_duration / self.stats.total_requests
time_avg = self.stats.total_requests_time / self.stats.total_requests
print "[avg req_time: " + str(time_avg) + ", dur: " + str(duration_avg) +
"] [current req_time: " + str(request_time) + ", dur: " + str(duration) + "] [max req_time: " +
str(self.stats.max_time) + ", dur: " + str(self.stats.max_duration) + "] reqs: " +
str(self.stats.total_requests)
raise gen.Return(body)


I tried to play a bit with the async class (Simple vs curl), the max_clients size, but I don't understand what is the best tune in my case.
But










share|improve this question






















  • My bet is that it's an elastic's, not AsyncHTTP's degradation. Have you tried monitoring elastic's performance?

    – Fian
    Mar 27 at 7:17












  • @Fian yes, it's not, I printed the took in ms of every query respond

    – ItayB
    Mar 27 at 8:05

















0















Setup: Python 2.7.15, Tornado 5.1



I have a web-server machine that handles ~40 /recommend requests per second.
The average response time is 25ms, but there's a big divergence (some requests can take more than 500ms).



Each request generates between 1-8 Elasticsearch queries (HTTP requests) internally.
Each Elasticsearch query can take between 1-150ms.



The Elasticsearch requests are handled synchronously via elasticsearch-dsl library.



The goal is to reduce the i/o waiting time (queries to Elasticsearch) and handle more requests per second so I can reduce the number of machines.
One thing is unacceptable - I don't want to increase the average handle time (25ms).



I found some tornado-elasticsearch implementations on the web, but since I need to use only one endpoint to Elasticsearch (/_search) I am trying to do that alone.



Below there's a degenerated implementation of my web-server. With the same load (~40 request per second) the average request response time increased to 200ms!



Digging in, I see that the internal async handle time (queries to Elasticsearch) is not stable and the time takes to each fetch call might be different, and the total average (in ab load test) is high.



I'm using ab to simulate the load and measure it internally by printing the current fetch handle time, average fetch handle time and maximum handle time.
When doing one request at a time (concurrency 1):
ab -p es-query-rcom.txt -T application/json -n 1000 -c 1 -k 'http://localhost:5002/recommend'



my prints looks like: [avg req_time: 3, dur: 3] [current req_time: 2, dur: 3] [max req_time: 125, dur: 125] reqs: 8000



But when I try to increase the concurrency (up to 8): ab -p es-query-rcom.txt -T application/json -n 1000 -c 8 -k 'http://localhost:5002/recommend'



now my prints looks like: [avg req_time: 6, dur: 13] [current req_time: 4, dur: 4] [max req_time: 73, dur: 84] reqs: 8000



The average req is now x2 slower (or x4 by my measurements)!
What do I miss here? why do I see this degradation?



web_server.py:



import tornado
from tornado.httpclient import AsyncHTTPClient
from tornado.options import define, options
from tornado.httpserver import HTTPServer
from web_handler import WebHandler

SERVICE_NAME = 'web_server'
NUM_OF_PROCESSES = 1


class Statistics(object):
def __init__(self):
self.total_requests = 0
self.total_requests_time = 0
self.total_duration = 0
self.max_time = 0
self.max_duration = 0


class RcomService(object):
def __init__(self):
print 'initializing RcomService...'
AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient", max_clients=3)
self.stats = Statistics()

def start(self, port):
define("port", default=port, type=int)
db = self.get_db(self.stats)
routes = self.generate_routes(db)
app = tornado.web.Application(routes)
http_server = HTTPServer(app, xheaders=True)
http_server.bind(options.port)
http_server.start(NUM_OF_PROCESSES)
tornado.ioloop.IOLoop.current().start()

@staticmethod
def generate_routes(db):
return [
(r"/recommend", WebHandler, dict(db=db))
]

@staticmethod
def get_db(stats):
return
'stats': stats



def main():
port = 5002
print('starting %s on port %s', SERVICE_NAME, port)

rcom_service = RcomService()
rcom_service.start(port)


if __name__ == '__main__':
main()


web_handler.py:



import time
import ujson
from tornado import gen
from tornado.gen import coroutine
from tornado.httpclient import AsyncHTTPClient
from tornado.web import RequestHandler


class WebHandler(RequestHandler):
def initialize(self, db):
self.stats = db['stats']

@coroutine
def post(self, *args, **kwargs):
result = yield self.wrapper_innear_loop([, , , , , , , ]) # dummy queries (empty)
self.write(
'res': result
)

@coroutine
def wrapper_innear_loop(self, queries):
result = []
for q in queries: # queries are performed serially
res = yield self.async_fetch_gen(q)
result.append(res)
raise gen.Return(result)

@coroutine
def async_fetch_gen(self, query):
url = 'http://localhost:9200/my_index/_search'

headers =
'Content-Type': 'application/json',
'Connection': 'keep-alive'


http_client = AsyncHTTPClient()
start_time = int(round(time.time() * 1000))
response = yield http_client.fetch(url, method='POST', body=ujson.dumps(query), headers=headers)
end_time = int(round(time.time() * 1000))
duration = end_time - start_time
body = ujson.loads(response.body)
request_time = int(round(response.request_time * 1000))
self.stats.total_requests += 1
self.stats.total_requests_time += request_time
self.stats.total_duration += duration
if self.stats.max_time < request_time:
self.stats.max_time = request_time
if self.stats.max_duration < duration:
self.stats.max_duration = duration
duration_avg = self.stats.total_duration / self.stats.total_requests
time_avg = self.stats.total_requests_time / self.stats.total_requests
print "[avg req_time: " + str(time_avg) + ", dur: " + str(duration_avg) +
"] [current req_time: " + str(request_time) + ", dur: " + str(duration) + "] [max req_time: " +
str(self.stats.max_time) + ", dur: " + str(self.stats.max_duration) + "] reqs: " +
str(self.stats.total_requests)
raise gen.Return(body)


I tried to play a bit with the async class (Simple vs curl), the max_clients size, but I don't understand what is the best tune in my case.
But










share|improve this question






















  • My bet is that it's an elastic's, not AsyncHTTP's degradation. Have you tried monitoring elastic's performance?

    – Fian
    Mar 27 at 7:17












  • @Fian yes, it's not, I printed the took in ms of every query respond

    – ItayB
    Mar 27 at 8:05













0












0








0








Setup: Python 2.7.15, Tornado 5.1



I have a web-server machine that handles ~40 /recommend requests per second.
The average response time is 25ms, but there's a big divergence (some requests can take more than 500ms).



Each request generates between 1-8 Elasticsearch queries (HTTP requests) internally.
Each Elasticsearch query can take between 1-150ms.



The Elasticsearch requests are handled synchronously via elasticsearch-dsl library.



The goal is to reduce the i/o waiting time (queries to Elasticsearch) and handle more requests per second so I can reduce the number of machines.
One thing is unacceptable - I don't want to increase the average handle time (25ms).



I found some tornado-elasticsearch implementations on the web, but since I need to use only one endpoint to Elasticsearch (/_search) I am trying to do that alone.



Below there's a degenerated implementation of my web-server. With the same load (~40 request per second) the average request response time increased to 200ms!



Digging in, I see that the internal async handle time (queries to Elasticsearch) is not stable and the time takes to each fetch call might be different, and the total average (in ab load test) is high.



I'm using ab to simulate the load and measure it internally by printing the current fetch handle time, average fetch handle time and maximum handle time.
When doing one request at a time (concurrency 1):
ab -p es-query-rcom.txt -T application/json -n 1000 -c 1 -k 'http://localhost:5002/recommend'



my prints looks like: [avg req_time: 3, dur: 3] [current req_time: 2, dur: 3] [max req_time: 125, dur: 125] reqs: 8000



But when I try to increase the concurrency (up to 8): ab -p es-query-rcom.txt -T application/json -n 1000 -c 8 -k 'http://localhost:5002/recommend'



now my prints looks like: [avg req_time: 6, dur: 13] [current req_time: 4, dur: 4] [max req_time: 73, dur: 84] reqs: 8000



The average req is now x2 slower (or x4 by my measurements)!
What do I miss here? why do I see this degradation?



web_server.py:



import tornado
from tornado.httpclient import AsyncHTTPClient
from tornado.options import define, options
from tornado.httpserver import HTTPServer
from web_handler import WebHandler

SERVICE_NAME = 'web_server'
NUM_OF_PROCESSES = 1


class Statistics(object):
def __init__(self):
self.total_requests = 0
self.total_requests_time = 0
self.total_duration = 0
self.max_time = 0
self.max_duration = 0


class RcomService(object):
def __init__(self):
print 'initializing RcomService...'
AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient", max_clients=3)
self.stats = Statistics()

def start(self, port):
define("port", default=port, type=int)
db = self.get_db(self.stats)
routes = self.generate_routes(db)
app = tornado.web.Application(routes)
http_server = HTTPServer(app, xheaders=True)
http_server.bind(options.port)
http_server.start(NUM_OF_PROCESSES)
tornado.ioloop.IOLoop.current().start()

@staticmethod
def generate_routes(db):
return [
(r"/recommend", WebHandler, dict(db=db))
]

@staticmethod
def get_db(stats):
return
'stats': stats



def main():
port = 5002
print('starting %s on port %s', SERVICE_NAME, port)

rcom_service = RcomService()
rcom_service.start(port)


if __name__ == '__main__':
main()


web_handler.py:



import time
import ujson
from tornado import gen
from tornado.gen import coroutine
from tornado.httpclient import AsyncHTTPClient
from tornado.web import RequestHandler


class WebHandler(RequestHandler):
def initialize(self, db):
self.stats = db['stats']

@coroutine
def post(self, *args, **kwargs):
result = yield self.wrapper_innear_loop([, , , , , , , ]) # dummy queries (empty)
self.write(
'res': result
)

@coroutine
def wrapper_innear_loop(self, queries):
result = []
for q in queries: # queries are performed serially
res = yield self.async_fetch_gen(q)
result.append(res)
raise gen.Return(result)

@coroutine
def async_fetch_gen(self, query):
url = 'http://localhost:9200/my_index/_search'

headers =
'Content-Type': 'application/json',
'Connection': 'keep-alive'


http_client = AsyncHTTPClient()
start_time = int(round(time.time() * 1000))
response = yield http_client.fetch(url, method='POST', body=ujson.dumps(query), headers=headers)
end_time = int(round(time.time() * 1000))
duration = end_time - start_time
body = ujson.loads(response.body)
request_time = int(round(response.request_time * 1000))
self.stats.total_requests += 1
self.stats.total_requests_time += request_time
self.stats.total_duration += duration
if self.stats.max_time < request_time:
self.stats.max_time = request_time
if self.stats.max_duration < duration:
self.stats.max_duration = duration
duration_avg = self.stats.total_duration / self.stats.total_requests
time_avg = self.stats.total_requests_time / self.stats.total_requests
print "[avg req_time: " + str(time_avg) + ", dur: " + str(duration_avg) +
"] [current req_time: " + str(request_time) + ", dur: " + str(duration) + "] [max req_time: " +
str(self.stats.max_time) + ", dur: " + str(self.stats.max_duration) + "] reqs: " +
str(self.stats.total_requests)
raise gen.Return(body)


I tried to play a bit with the async class (Simple vs curl), the max_clients size, but I don't understand what is the best tune in my case.
But










share|improve this question














Setup: Python 2.7.15, Tornado 5.1



I have a web-server machine that handles ~40 /recommend requests per second.
The average response time is 25ms, but there's a big divergence (some requests can take more than 500ms).



Each request generates between 1-8 Elasticsearch queries (HTTP requests) internally.
Each Elasticsearch query can take between 1-150ms.



The Elasticsearch requests are handled synchronously via elasticsearch-dsl library.



The goal is to reduce the i/o waiting time (queries to Elasticsearch) and handle more requests per second so I can reduce the number of machines.
One thing is unacceptable - I don't want to increase the average handle time (25ms).



I found some tornado-elasticsearch implementations on the web, but since I need to use only one endpoint to Elasticsearch (/_search) I am trying to do that alone.



Below there's a degenerated implementation of my web-server. With the same load (~40 request per second) the average request response time increased to 200ms!



Digging in, I see that the internal async handle time (queries to Elasticsearch) is not stable and the time takes to each fetch call might be different, and the total average (in ab load test) is high.



I'm using ab to simulate the load and measure it internally by printing the current fetch handle time, average fetch handle time and maximum handle time.
When doing one request at a time (concurrency 1):
ab -p es-query-rcom.txt -T application/json -n 1000 -c 1 -k 'http://localhost:5002/recommend'



my prints looks like: [avg req_time: 3, dur: 3] [current req_time: 2, dur: 3] [max req_time: 125, dur: 125] reqs: 8000



But when I try to increase the concurrency (up to 8): ab -p es-query-rcom.txt -T application/json -n 1000 -c 8 -k 'http://localhost:5002/recommend'



now my prints looks like: [avg req_time: 6, dur: 13] [current req_time: 4, dur: 4] [max req_time: 73, dur: 84] reqs: 8000



The average req is now x2 slower (or x4 by my measurements)!
What do I miss here? why do I see this degradation?



web_server.py:



import tornado
from tornado.httpclient import AsyncHTTPClient
from tornado.options import define, options
from tornado.httpserver import HTTPServer
from web_handler import WebHandler

SERVICE_NAME = 'web_server'
NUM_OF_PROCESSES = 1


class Statistics(object):
def __init__(self):
self.total_requests = 0
self.total_requests_time = 0
self.total_duration = 0
self.max_time = 0
self.max_duration = 0


class RcomService(object):
def __init__(self):
print 'initializing RcomService...'
AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient", max_clients=3)
self.stats = Statistics()

def start(self, port):
define("port", default=port, type=int)
db = self.get_db(self.stats)
routes = self.generate_routes(db)
app = tornado.web.Application(routes)
http_server = HTTPServer(app, xheaders=True)
http_server.bind(options.port)
http_server.start(NUM_OF_PROCESSES)
tornado.ioloop.IOLoop.current().start()

@staticmethod
def generate_routes(db):
return [
(r"/recommend", WebHandler, dict(db=db))
]

@staticmethod
def get_db(stats):
return
'stats': stats



def main():
port = 5002
print('starting %s on port %s', SERVICE_NAME, port)

rcom_service = RcomService()
rcom_service.start(port)


if __name__ == '__main__':
main()


web_handler.py:



import time
import ujson
from tornado import gen
from tornado.gen import coroutine
from tornado.httpclient import AsyncHTTPClient
from tornado.web import RequestHandler


class WebHandler(RequestHandler):
def initialize(self, db):
self.stats = db['stats']

@coroutine
def post(self, *args, **kwargs):
result = yield self.wrapper_innear_loop([, , , , , , , ]) # dummy queries (empty)
self.write(
'res': result
)

@coroutine
def wrapper_innear_loop(self, queries):
result = []
for q in queries: # queries are performed serially
res = yield self.async_fetch_gen(q)
result.append(res)
raise gen.Return(result)

@coroutine
def async_fetch_gen(self, query):
url = 'http://localhost:9200/my_index/_search'

headers =
'Content-Type': 'application/json',
'Connection': 'keep-alive'


http_client = AsyncHTTPClient()
start_time = int(round(time.time() * 1000))
response = yield http_client.fetch(url, method='POST', body=ujson.dumps(query), headers=headers)
end_time = int(round(time.time() * 1000))
duration = end_time - start_time
body = ujson.loads(response.body)
request_time = int(round(response.request_time * 1000))
self.stats.total_requests += 1
self.stats.total_requests_time += request_time
self.stats.total_duration += duration
if self.stats.max_time < request_time:
self.stats.max_time = request_time
if self.stats.max_duration < duration:
self.stats.max_duration = duration
duration_avg = self.stats.total_duration / self.stats.total_requests
time_avg = self.stats.total_requests_time / self.stats.total_requests
print "[avg req_time: " + str(time_avg) + ", dur: " + str(duration_avg) +
"] [current req_time: " + str(request_time) + ", dur: " + str(duration) + "] [max req_time: " +
str(self.stats.max_time) + ", dur: " + str(self.stats.max_duration) + "] reqs: " +
str(self.stats.total_requests)
raise gen.Return(body)


I tried to play a bit with the async class (Simple vs curl), the max_clients size, but I don't understand what is the best tune in my case.
But







python python-2.7 tornado






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Mar 25 at 21:14









ItayBItayB

3,2905 gold badges30 silver badges46 bronze badges




3,2905 gold badges30 silver badges46 bronze badges












  • My bet is that it's an elastic's, not AsyncHTTP's degradation. Have you tried monitoring elastic's performance?

    – Fian
    Mar 27 at 7:17












  • @Fian yes, it's not, I printed the took in ms of every query respond

    – ItayB
    Mar 27 at 8:05

















  • My bet is that it's an elastic's, not AsyncHTTP's degradation. Have you tried monitoring elastic's performance?

    – Fian
    Mar 27 at 7:17












  • @Fian yes, it's not, I printed the took in ms of every query respond

    – ItayB
    Mar 27 at 8:05
















My bet is that it's an elastic's, not AsyncHTTP's degradation. Have you tried monitoring elastic's performance?

– Fian
Mar 27 at 7:17






My bet is that it's an elastic's, not AsyncHTTP's degradation. Have you tried monitoring elastic's performance?

– Fian
Mar 27 at 7:17














@Fian yes, it's not, I printed the took in ms of every query respond

– ItayB
Mar 27 at 8:05





@Fian yes, it's not, I printed the took in ms of every query respond

– ItayB
Mar 27 at 8:05












1 Answer
1






active

oldest

votes


















0














Increased time may be because with concurrency==1, CPU was under-utilized and with c==8 it's 100%+ utilized and is unable to catch up with all requests. Example, abstract CPU can process 1000 operations/sec, to send a request it takes 50 CPU ops and to read a request result it takes 50 CPU ops too. When you have 5 RPS your CPU is 50% utilized and average request time is 50 ms (to send a req.) + request time + 50 ms (to read a req.). But when you have, for example, 40 RPS (8 times more than 5 RPS), your CPU would be over-utilized by 400% and some finished requests would be waiting to be parsed, so average request time now is 50 ms + request time + CPU wait time + 50 ms.



To sum up, my advise would be to check a CPU utilization on both loads and, to be sure, to profile how much time does it takes to send a request and parse a response, CPU may be your bottleneck.






share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55346500%2ftornado-asynchttpclient-performance-degradation%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    Increased time may be because with concurrency==1, CPU was under-utilized and with c==8 it's 100%+ utilized and is unable to catch up with all requests. Example, abstract CPU can process 1000 operations/sec, to send a request it takes 50 CPU ops and to read a request result it takes 50 CPU ops too. When you have 5 RPS your CPU is 50% utilized and average request time is 50 ms (to send a req.) + request time + 50 ms (to read a req.). But when you have, for example, 40 RPS (8 times more than 5 RPS), your CPU would be over-utilized by 400% and some finished requests would be waiting to be parsed, so average request time now is 50 ms + request time + CPU wait time + 50 ms.



    To sum up, my advise would be to check a CPU utilization on both loads and, to be sure, to profile how much time does it takes to send a request and parse a response, CPU may be your bottleneck.






    share|improve this answer



























      0














      Increased time may be because with concurrency==1, CPU was under-utilized and with c==8 it's 100%+ utilized and is unable to catch up with all requests. Example, abstract CPU can process 1000 operations/sec, to send a request it takes 50 CPU ops and to read a request result it takes 50 CPU ops too. When you have 5 RPS your CPU is 50% utilized and average request time is 50 ms (to send a req.) + request time + 50 ms (to read a req.). But when you have, for example, 40 RPS (8 times more than 5 RPS), your CPU would be over-utilized by 400% and some finished requests would be waiting to be parsed, so average request time now is 50 ms + request time + CPU wait time + 50 ms.



      To sum up, my advise would be to check a CPU utilization on both loads and, to be sure, to profile how much time does it takes to send a request and parse a response, CPU may be your bottleneck.






      share|improve this answer

























        0












        0








        0







        Increased time may be because with concurrency==1, CPU was under-utilized and with c==8 it's 100%+ utilized and is unable to catch up with all requests. Example, abstract CPU can process 1000 operations/sec, to send a request it takes 50 CPU ops and to read a request result it takes 50 CPU ops too. When you have 5 RPS your CPU is 50% utilized and average request time is 50 ms (to send a req.) + request time + 50 ms (to read a req.). But when you have, for example, 40 RPS (8 times more than 5 RPS), your CPU would be over-utilized by 400% and some finished requests would be waiting to be parsed, so average request time now is 50 ms + request time + CPU wait time + 50 ms.



        To sum up, my advise would be to check a CPU utilization on both loads and, to be sure, to profile how much time does it takes to send a request and parse a response, CPU may be your bottleneck.






        share|improve this answer













        Increased time may be because with concurrency==1, CPU was under-utilized and with c==8 it's 100%+ utilized and is unable to catch up with all requests. Example, abstract CPU can process 1000 operations/sec, to send a request it takes 50 CPU ops and to read a request result it takes 50 CPU ops too. When you have 5 RPS your CPU is 50% utilized and average request time is 50 ms (to send a req.) + request time + 50 ms (to read a req.). But when you have, for example, 40 RPS (8 times more than 5 RPS), your CPU would be over-utilized by 400% and some finished requests would be waiting to be parsed, so average request time now is 50 ms + request time + CPU wait time + 50 ms.



        To sum up, my advise would be to check a CPU utilization on both loads and, to be sure, to profile how much time does it takes to send a request and parse a response, CPU may be your bottleneck.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Mar 27 at 11:02









        FianFian

        1,4231 gold badge6 silver badges15 bronze badges




        1,4231 gold badge6 silver badges15 bronze badges


















            Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.







            Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.



















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55346500%2ftornado-asynchttpclient-performance-degradation%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            SQL error code 1064 with creating Laravel foreign keysForeign key constraints: When to use ON UPDATE and ON DELETEDropping column with foreign key Laravel error: General error: 1025 Error on renameLaravel SQL Can't create tableLaravel Migration foreign key errorLaravel php artisan migrate:refresh giving a syntax errorSQLSTATE[42S01]: Base table or view already exists or Base table or view already exists: 1050 Tableerror in migrating laravel file to xampp serverSyntax error or access violation: 1064:syntax to use near 'unsigned not null, modelName varchar(191) not null, title varchar(191) not nLaravel cannot create new table field in mysqlLaravel 5.7:Last migration creates table but is not registered in the migration table

            용인 삼성생명 블루밍스 목차 통계 역대 감독 선수단 응원단 경기장 같이 보기 외부 링크 둘러보기 메뉴samsungblueminx.comeh선수 명단용인 삼성생명 블루밍스용인 삼성생명 블루밍스ehsamsungblueminx.comeheheheh

            155 수학 과학 기타 둘러보기 메뉴eh추가해eh문서를 완성해