tornado, python的高併發微服務,從入門到部署上線

1.介紹

使用python編寫的網絡框架和高性能的異步網絡庫
使用大量連接、長輪詢、websockets應用

  • 優勢:微服務、高性能、異步支持
  • 缺點:輪子少不像Django、Flask等框架有大量插件支持;缺少最佳實踐,使用的公司不多,學習資料少

使用場景
構建微服務,不適合複雜的CMS(內容管理系統)應用;適合構建網站或者App後端微服務

學習資料

  • 官方文檔:https://www.tornadoweb.org/en/stable/;
  • github:https://github.com/tornadoweb/tornado
  • 書:《Introduction to Tornado》

2.安裝和使用

安裝:pip install tornado

下載源碼學習示例代碼:git clone https://github.com/tornadoweb/tornado.git
(沒有git的話先安裝git,yum -y install git)

官網上拷hello,word代碼

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

1.編寫一個hello world 應用 app.py,以上代碼
2.使用python app.py 啓動tornado應用
3.使用curl或者瀏覽器驗證:curl http://127.0.0.1:8888

3.Tornado web 主要模塊

主要模塊
tornado.web ApplicationRequestHandler 類處理http請求
tornado.template 模版渲染
tornado.routing 處理路由

HTTP服務器和客戶端模塊
tornado.httpserver 非阻塞HTTP客戶端
tornado.httpclient 異步HTTP客戶端

異步networking
tornado.ioloop 事件循環
tornado.iostream 非阻塞socket封裝
tornado.tcpservertornado.tcpclient

協程和併發
tornado.gen 協程模塊
tornado.locks/tornado.queues 同步、協程隊列模塊

4.三種啓動方式

app.listen()這個方法只能在單進程模式中使用。
對於app.listen()與方式二中的手動創建HTTPServer實例這兩種方式,建議大家先使用後者即創建HTTPServer實例的方式,因爲其對於理解tornado web應用工作流程的完整性有幫助,便於大家記憶tornado開發的模塊組成和程序結構;在熟練使用後,可以改爲簡寫。

第一種啓動方式:單進程

import tornado.web         # web服務
import tornado.ioloop      # I/O 時間循環
import tornado.httpserver  # 新引入httpserver模塊,單線程的http服務
 
class Mainhandler(tornado.web.RequestHandler):
    def get(self):
        self.write("hello world!")
 
# 建立路由表
app = tornado.web.Application([
        (r"/index", Mainhandler),
    ])
 
if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(8000)
    # tornado.ioloop.IOLoop.current().start()
    tornado.ioloop.IOLoop.instance().start()  # 開始事件

在這一修改版本中,我們引入了tornado.httpserver模塊,顧名思義,它就是tornado的HTTP服務器實現。
我們創建了一個HTTP服務器實例http_server,因爲服務器要服務於我們剛剛建立的web應用,將接收到的客戶端請求通過web應用中的路由映射表引導到對應的handler中,所以在構建http_server對象的時候需要傳出web應用對象app。http_server.listen(8000)將服務器綁定到8000端口。
實際上一版代碼中app.listen(8000)正是對這一過程的簡寫。

第二種啓動方式:多進程


```python
import tornado.web         # web服務
import tornado.ioloop      # I/O 時間循環
import tornado.httpserver  # 新引入httpserver模塊,單線程的http服務
 
class Mainhandler(tornado.web.RequestHandler):
    def get(self):
        self.write("hello world!")
 
# 建立路由表
app = tornado.web.Application([
        (r"/index", Mainhandler),
    ])
 
if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.bind(8000)
    http_server.start(3)
    # tornado.ioloop.IOLoop.current().start()
    tornado.ioloop.IOLoop.instance().start()  # 開始事件

http_server.bind(port)方法是將服務器綁定到指定端口。
http_server.start(num_processes=1)方法指定開啓幾個進程,參數num_processes默認值爲1,即默認僅開啓一個進程;如果num_processes爲None或者<=0,則自動根據機器硬件的cpu核芯數創建同等數目的子進程;如果num_processes>0,則創建num_processes個子進程。
前面寫的http_server.listen(8000)實際上就等同於:http_server.bind(8000) http_server.start(1)這兩行代碼。

第三種啓動方式:多進程

import tornado.web         # web服務
import tornado.ioloop      # I/O 時間循環
import tornado.httpserver  # 新引入httpserver模塊,單線程的http服務
 
class Mainhandler(tornado.web.RequestHandler):
    def get(self):
        self.write("hello world!")
 
# 建立路由表
app = tornado.web.Application([
        (r"/index", Mainhandler),
    ])
 
if __name__ == "__main__":
    sockets = tornado.netutil.bind_sockets(8888)
    tornado.process.fork_processes(0)  # 10
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.add_sockets(sockets)
    # tornado.ioloop.IOLoop.current().start()
    tornado.ioloop.IOLoop.instance().start()  # 開始事件

我使用第三種方式部署服務

5.編寫高併發服務

get_data有方法裏面有多個數據接口,使用協程可以提高服務的併發能力

# -*-coding:utf8-*-
"""
-----
"""
import tornado.ioloop
import tornado.web
import tornado.httpserver
import tornado.options
from tornado.concurrent import run_on_executor
import http.client
from concurrent.futures import ThreadPoolExecutor


class MainHandler(tornado.web.RequestHandler):
    executor = ThreadPoolExecutor(10)  # 起線程池,由當前RequestHandler持有
    @tornado.gen.coroutine
    def get(self):
        data = yield self.get_data(parameters)
        
    @run_on_executor
    def get_data(self, appId, userId, Client_parameters):
        return data

class TestHandler(tornado.web.RequestHandler):
    def get(self):
        self.write('ok')


def make_app():
    return tornado.web.Application([
        (r"/", MainHandler), (r"/test", TestHandler)
    ])


if __name__ == "__main__":
    app = make_app()
    sockets = tornado.netutil.bind_sockets(8000)
    tornado.process.fork_processes(0)  # 10
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.add_sockets(sockets)
    tornado.ioloop.IOLoop.instance().start()  # 開始事件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章