How to analyze gunicorn Arbiter source code
As mentioned earlier, Arbiter is the core of the gunicorn master process. Arbiter is mainly responsible for managing worker processes, including starting, monitoring, and killing worker processes. At the same time, Arbiter can also hot update (reload) App applications or upgrade gunicorn online when certain signals occur. The core code of Arbiter is in one file, and the amount of code is not large. The source code is here: https://github.com/benoitc/gunicorn.
Arbiter mainly has the following methods:
setup:
Processing configuration items, the most important ones are the number of workers and the worker working model
init_signal:
Register signal processing function
handle_xxx:
Specific processing function for each signal
kill_worker, kill_workers:
Send a signal to the worker process
spawn_worker, spawn_workers:
Fork to create a new worker Process
murder_workers:
Kill worker processes that have not responded for a period of time
manage_workers:
Based on the number of workers in the configuration file and the number of currently active workers, decide whether to fork or kill the worker process
reexec:
After receiving the signal SIGUSR2 call, online Upgrade gunicorn
#reload:
After receiving the signal SIGHUP call, the worker process will be started based on the new configuration and the previous worker process will be killed
sleep:
When there is no signal processing, use the select timeout to sleep and can be woken up
wakeup:
Wake up the process by writing messages to the pipe
run:
Main loop
The only functions of Arbiter that are actually called by other codes (Application) __init__ and run methods, in one line of code:
Arbiter(self).run()
The self in the above code is the Application instance, where_ _init__ calls setup to set configuration items. The following is the pseudo code of the run method
def run() self.init_signal() self.LISTENERS = create_sockets(self.cfg, self.log) self.manage_workers() while True: if no signal in SIG_QUEUE self.sleep() else: handle_signal()
## About fork child process
fork child process The code is in spawn_worker, the source code is as follows: Arbiter.spawn_worker
1 # prefork.py 2 import sys 3 import socket 4 import select 5 import os 6 import time 7 8 def do_sub_process(): 9 pid = os.fork()10 if pid < 0:11 print 'fork error'12 sys.exit(-1)13 elif pid > 0:14 print 'fork sub process %d' % pid15 return16 17 # must be child process18 time.sleep(1)19 print 'sub process will exit', os.getpid(), os.getppid()20 sys.exit(0)21 22 def main():23 sub_num = 224 for i in range(sub_num):25 do_sub_process()26 time.sleep(10)27 print 'main process will exit', os.getpid()28 29 if __name__ == '__main__':30 main()
sys.exit to ensure the end of the child process, otherwise the for loop in the main function will continue. , and the subsequent logic. Comment out line 19 and run again, and you will understand by looking at the output.
About killing child processes
It is very simple for the master process to kill the worker process. It sends a signal directly. The source code is as follows:1 def kill_worker(self, pid, sig): 2 """\ 3 Kill a worker 4 5 :attr pid: int, worker pid 6 :attr sig: `signal.SIG*` value 7 """ 8 try: 9 os.kill(pid, sig)10 except OSError as e:11 if e.errno == errno.ESRCH:12 try:13 worker = self.WORKERS.pop(pid)14 worker.tmp.close()15 self.cfg.worker_exit(self, worker)16 return17 except (KeyError, OSError):18 return19 raise
About sleep and wakeup
Let’s take a look at Arbiter’s sleep and wakeup. Arbiter will "sleep" when there is no signal to process. Of course, it does not actually call time.sleep, otherwise the signal will not be processed immediately when it comes. The implementation here is more clever, using pipes and select timeout. Just look at the code and you will knowdef sleep(self): """\ Sleep until PIPE is readable or we timeout. A readable PIPE means a signal occurred. """ ready = select.select([self.PIPE[0]], [], [], 1.0) # self.PIPE = os.pipe() if not ready[0]: return while os.read(self.PIPE[0], 1): pass
os.
pipe
()
- Create a pipe. Return a pair of file descriptors
(r,w)
usable for reading and writing, respectively.
def wakeup(self): """ Wake up the arbiter by writing to the PIPE """ os.write(self.PIPE[1], b'.')
Finally, the signal processing of Arbiter is attached:
Exit, INT: Quick shutdownTERM: Graceful shutdown. Waits for the worker to complete its current request until it times out.HUP: Reload configuration, start new worker processes with new configuration, and shut down old worker processes gracefully. Gunicorn will also load the new version if the application is not preloaded (using the --preload option).
TTIN: Increase the number of processes by one
TTOU: Decrease the number of processes by one
USR1: Reopen the log file
USR2: Upgrade on the fly Gunicorn. A separate term signal should be used to terminate the old process. This signal can also be used to use preloaded new versions of the application.
Winch: Gracefully shut down worker processes when Gunicorn is daemonized.
The above is the detailed content of How to analyze gunicorn Arbiter source code. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



What is the Python GIL, how does it work, and how does it affect gunicorn. Which Gunicorn worker type should I choose for production? Python has a global lock (GIL) which only allows one thread to run (i.e. interpret bytecode). In my opinion, understanding how Python handles concurrency is essential if you want to optimize your Python services. Python and gunicorn give you different ways of handling concurrency, and since there's no magic bullet that covers all use cases, it's a good idea to understand the options, tradeoffs, and advantages of each option. Gunicorn worker typeGunico

Flask application deployment: Comparison of Gunicorn vs suWSGI Introduction: Flask, as a lightweight Python Web framework, is loved by many developers. When deploying a Flask application to a production environment, choosing the appropriate Server Gateway Interface (SGI) is a crucial decision. Gunicorn and uWSGI are two common SGI servers. This article will describe them in detail.

Basic concepts and functions of Gunicorn Gunicorn is a tool for running WSGI servers in Python web applications. WSGI (Web Server Gateway Interface) is a specification defined by the Python language and is used to define the communication interface between web servers and web applications. Gunicorn enables Python web applications to be deployed and run in production environments by implementing the WSGI specification. The function of Gunicorn is to

How to deploy Flask application using Gunicorn? Flask is a lightweight Python Web framework that is widely used to develop various types of Web applications. Gunicorn (GreenUnicorn) is a Python-based HTTP server used to run WSGI (WebServerGatewayInterface) applications. This article will introduce how to use Gunicorn to deploy Flask applications, with

Gunicorn is a WSGI (HTTP server) web server gateway interface specification written in Python. It is a lightweight and efficient server specifically designed to run Python web applications. Its main features and functions include: 1. High performance, which can easily handle high concurrent requests; 2. Stable and reliable, which can provide durable long-term operation, greatly reducing the possibility of server crash; 3. Fault tolerance, which can do To maintain the stability of the service; 4. Multiple deployment methods, etc.

Gunicorn and Flask: The perfect deployment combination, specific code examples required Overview: It is very important for developers to choose the appropriate deployment method, especially for Python web applications. Among Python web frameworks, Flask is a very popular choice, and Gunicorn is a server for deploying Python applications. This article will introduce the combination of Gunicorn and Flask and provide some specific code examples to help readers

LINUX is a powerful operating system that is widely used in servers and development environments. CentOS is an open source operating system based on Red Hat Enterprise Linux (RHEL) and is widely used in server environments. Installing Gunicorn and partitioning on CentOS can improve the performance of the server. Performance and security, this article will detail how to install Gunicorn on CentOS and how to partition it. Install Gunicorn on CentOS Gunicorn is a Python WSGIHTTP server for running Python web applications. The following is how to install Gunicorn on CentOS.

How does Gunicorn improve the performance of Flask applications? With the rapid development of the Internet, the performance of web applications has become increasingly important for user experience and enterprise competitiveness. When handling high concurrent requests, the default development server of the Flask framework often cannot meet the demand. Therefore, we need to use Gunicorn (GreenUnicorn) to improve the performance of Flask applications. Gunicorn is a Python-based HTTP server that uses pre-forked
