gunicorn syncworker 源碼解析


  gunicorn支持不同的worker類型,同步或者異步,異步的話包括基於gevent、基於eventlet、基於Aiohttp(python版本需要大於3.3),也有多線程的版本。下面是gunicorn當前版本(19.6.0)支持的Worker類型:
  • sync
  • eventlet - Requires eventlet >= 0.9.7
  • gevent - Requires gevent >= 0.13
  • tornado - Requires tornado >= 0.2
  • gthread - Python 2 requires the futures package to be installed
  • gaiohttp - Requires Python 3.4 and aiohttp >= 0.21.5
本文主要對同步模型進行分析。同步模型實現(gunicorn.workers.sync.SyncWorker)繼承自gunicorn.workers.base.Worker,絕大多數方法都是定義在基類,包括
init_signal
    注冊信號處理函數
 
handle_xxx:
    各個信號具體的處理函數
 
notify:
    通知父進程自己還活着
 
run:
    需要子類實現的接口,用於處理具體的請求。
 
init_process:
    提供給Arbiter的接口,調用inti_signal和run方法
 
 
SyncWorker實現了run方法,對HTTP請求進程處理
def run(self):    
       if len(self.sockets) > 1:
            self.run_for_multiple(timeout) # 使用select
       else:
            self.run_for_one(timeout)        # 如果只有一個監聽socket,那么阻塞accept就行了
  run方法根據監聽的端口數量進行區分,如果只在一個端口監聽,那么調用accept; 如果是多個端口,那么用select輪訓再accept。不管哪種方式,新的連接請求到達后 都調用handle_request函數處理,源代碼如下:
  
    def handle_request(self, listener, req, client, addr):
        environ = {}
        resp = None
        try:
            self.cfg.pre_request(self, req)
            request_start = datetime.now()
            resp, environ = wsgi.create(req, client, addr,
                    listener.getsockname(), self.cfg)
            # Force the connection closed until someone shows
            # a buffering proxy that supports Keep-Alive to
            # the backend.
            resp.force_close()
            self.nr += 1
            if self.nr >= self.max_requests:
                self.log.info("Autorestarting worker after current request.")
                self.alive = False
            respiter = self.wsgi(environ, resp.start_response)
            try:
                if isinstance(respiter, environ['wsgi.file_wrapper']):
                    resp.write_file(respiter)
                else:
                    for item in respiter:
                        resp.write(item)
                resp.close()
                request_time = datetime.now() - request_start
                self.log.access(resp, req, environ, request_time)

  其中,調用到App的是下面這行代碼

   respiter = self.wsgi(environ, resp.start_response)
 
  前面提到 worker通過notify來向master進程做心跳,具體的代碼在WorkerTmp.py。原理很簡單:
    (1)首先通過tempfile.mkstemp創建一個臨時文件
    (2)worker進程在每次輪訓的時候修改該臨時文件的屬性
    
    def notify(self):
        try:
            self.spinner = (self.spinner + 1) % 2
            os.fchmod(self._tmp.fileno(), self.spinner)
        except AttributeError:
            # python < 2.6
            self._tmp.truncate(0)
            os.write(self._tmp.fileno(), b"X")

 

    (3)master進程檢查臨時文件最新一次修改時間是否超過閾值
    
    def last_update(self):
        return os.fstat(self._tmp.fileno()).st_ctime

 

references:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM