2013-08-13 33 views
5

Tôi đã phát triển một máy chủ http khá rộng rãi được viết bằng python sử dụng lốc xoáy. Nếu không đặt bất cứ điều gì đặc biệt, máy chủ sẽ chặn các yêu cầu và chỉ có thể xử lý một yêu cầu tại một thời điểm. Các yêu cầu về cơ bản truy cập dữ liệu (mysql/redis) và in nó ra trong json. Những yêu cầu này có thể mất tới một giây trong trường hợp xấu nhất. Vấn đề là một yêu cầu đến trong đó mất một thời gian dài (3s), sau đó một yêu cầu dễ dàng đến ngay lập tức sau đó sẽ mất 5ms để xử lý. Vì yêu cầu đầu tiên sẽ mất 3 giây, yêu cầu thứ hai không bắt đầu cho đến khi yêu cầu đầu tiên được thực hiện. Vì vậy, yêu cầu thứ hai mất> 3s để được xử lý.python http server, nhiều yêu cầu đồng thời

Làm cách nào để cải thiện tình trạng này? Tôi cần yêu cầu đơn giản thứ hai đó để bắt đầu thực hiện bất kể yêu cầu nào khác. Tôi mới đến python, và nhiều kinh nghiệm với apache/php, nơi không có khái niệm về hai yêu cầu riêng biệt ngăn chặn lẫn nhau. Tôi đã nhìn vào mod_python để mô phỏng ví dụ php, nhưng điều đó dường như cũng chặn. Tôi có thể thay đổi máy chủ lốc xoáy của mình để có được chức năng mà tôi muốn không? Ở khắp mọi nơi tôi đọc, nó nói rằng cơn lốc xoáy là rất tốt trong việc xử lý nhiều yêu cầu đồng thời.

Đây là mã demo mà tôi đang làm việc. Tôi có một lệnh ngủ mà tôi đang sử dụng để kiểm tra nếu đồng thời hoạt động. Ngủ một cách công bằng để kiểm tra đồng thời?

import tornado.httpserver 
import tornado.ioloop 
import tornado.web 
import tornado.gen 
import time 

class MainHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    @tornado.gen.engine 

    def handlePing1(self): 
     time.sleep(4)#simulating an expensive mysql call 
     self.write("response to browser ....") 
     self.finish() 

    def get(self): 
     start = time.time() 
     self.handlePing1() 
     #response = yield gen.Task(handlePing1)#i see tutorials around that suggest using something like this .... 

     print "done with request ...", self.request.path, round((time.time()-start),3) 



application = tornado.web.Application([ 
     (r"/.*", MainHandler), 
]) 

if __name__ == "__main__": 
    http_server = tornado.httpserver.HTTPServer(application) 
    port=8833; 
    http_server.listen(port) 
    print "listening on "+str(port); 
    tornado.ioloop.IOLoop.instance().start() 

Cảm ơn bạn đã được trợ giúp!

Trả lời

0

Tôi có cùng một vấn đề, nhưng không có lốc xoáy, không có mysql. Bạn có một kết nối cơ sở dữ liệu được chia sẻ với tất cả máy chủ không?

Tôi đã tạo một multiprocessing.Pool. Mỗi thiết bị có kết nối db riêng được cung cấp bởi hàm init. Tôi quấn mã chậm trong hàm và map nó vào Bể bơi. Vì vậy, tôi không có biến chia sẻ và kết nối.

Chế độ ngủ không chặn các chuỗi khác, nhưng giao dịch DB có thể chặn chuỗi.

Bạn cần thiết lập Bể bơi ở đầu mã của mình.

def spawn_pool(fishes=None): 
    global pool 
    from multiprocessing import Pool 
    def init(): 
     from storage import db #private connections 
     db.connect() #connections stored in db-framework and will be global in each process 
    pool = Pool(processes=fishes,initializer=init) 

if __name__ == "__main__": 
    spawn_pool(8) 


from storage import db #shared connection for quick-type requests. 

#code here 

if __name__ == "__main__": 
    start_server() 

Nhiều yêu cầu nhanh đồng thời có thể làm chậm một yêu cầu lớn, nhưng đồng thời này sẽ chỉ được đặt trên máy chủ cơ sở dữ liệu.

3

Chỉnh sửa: hãy nhớ rằng Redis cũng là một chuỗi duy nhất, vì vậy ngay cả khi bạn có yêu cầu đồng thời, nút cổ chai của bạn sẽ là Redis. Bạn sẽ không thể xử lý nhiều yêu cầu hơn vì Redis sẽ không thể xử lý chúng.

Tornado là máy chủ dựa trên chuỗi đơn, sự kiện.

Từ các tài liệu:

Bằng việc sử dụng mạng non-blocking I/O, Tornado có thể mở rộng lên tới hàng chục ngàn kết nối mở, làm cho nó lý tưởng cho việc bỏ phiếu dài, WebSockets, và các ứng dụng khác đòi hỏi phải có một kết nối lâu dài với mỗi người dùng.

Đồng thời trong cơn lốc xoáy đạt được thông qua gọi lại không đồng bộ. Ý tưởng là làm càng ít càng tốt trong vòng lặp sự kiện chính (đơn luồng) để tránh chặn và trì hoãn hoạt động i/o thông qua các cuộc gọi lại.

Nếu sử dụng các hoạt động không đồng bộ không hoạt động cho bạn (ví dụ: không có trình điều khiển không đồng bộ cho MySQL hoặc Redis), cách duy nhất để xử lý nhiều yêu cầu đồng thời hơn là chạy nhiều quy trình.

Cách dễ nhất là tiến hành các quy trình lốc xoáy của bạn với proxy ngược như HAProxy hoặc Nginx. Tài liệu về cơn lốc xoáy đề xuất Nginx: http://www.tornadoweb.org/en/stable/overview.html#running-tornado-in-production

Về cơ bản, bạn chạy nhiều phiên bản ứng dụng trên các cổng khác nhau. Ví dụ:

python app.py --port=8000 
python app.py --port=8001 
python app.py --port=8002 
python app.py --port=8003 

Nguyên tắc chung là chạy 1 quy trình cho mỗi lõi trên máy chủ của bạn.

Nginx sẽ chăm sóc cân bằng từng yêu cầu đến với các chương trình phụ trợ khác nhau. Vì vậy, nếu một trong những yêu cầu là chậm (~ 3s) bạn có n-1 quá trình khác lắng nghe cho các yêu cầu đến. Có thể - và rất có thể - tất cả các quy trình sẽ bận xử lý yêu cầu chậm, trong đó các yêu cầu trường hợp sẽ được xếp hàng đợi và xử lý khi bất kỳ quá trình nào trở nên miễn phí, ví dụ: đã xử lý xong yêu cầu.

Tôi thực sự khuyên bạn nên bắt đầu với Nginx trước khi thử HAProxy vì sau này nâng cao hơn một chút và do đó phức tạp hơn một chút để thiết lập đúng (nhiều công tắc để tinh chỉnh).

Hy vọng điều này sẽ hữu ích. Key take-away: Tornado là tuyệt vời cho async I/O, ít hơn cho CPU nặng khối lượng công việc.