之前说过了,swift是怎样根据配置文件进行服务的启动的,现在来说一下proxy-server的启动过程,到现在为止,系统已经找到了swift-proxy-server文件,并进行执行,看下该文件的代码
import sys
from swift.common.utils import parse_options
from swift.common.wsgi import run_wsgi
if __name__ == '__main__':
conf_file, options = parse_options()
sys.exit(run_wsgi(conf_file, 'proxy-server', **options))
也即主要的函数run_wsgi文件是在common下的wsgi文件中的
def run_wsgi(conf_path, app_section, *args, **kwargs):
"""
运行服务制定的进程数目
Runs the server using the specified number of workers.
:param conf_path: Path to paste.deploy style configuration file/directory
:param app_section: App name from conf file to load config from,制定的配置文件名称‘proxy_server’
:returns: 0 if successful, nonzero otherwise,返回0表示成功,非0 失败
"""
# Load configuration, Set logger and Load request processor
try:
#_initrp函数定义在514行,根据配置加载日志记录器,还有,指定的/etc/swift/swift-proxy-server.conf文件中的节proxy-server中的内容记录在了conf中
(conf, logger, log_name) = \
_initrp(conf_path, app_section, *args, **kwargs)
except ConfigFileError as e:
print(e)
return 1
# bind to address and port 绑定地址和端口号
try:
sock = get_socket(conf)
#至此已经根据配置文件将端口ip地址绑定完毕
except ConfigFilePortError:
msg = 'bind_port wasn\'t properly set in the config file. ' \
'It must be explicitly set to a valid port number.'
logger.error(msg)
print(msg)
return 1
# remaining tasks should not require elevated privileges,设置当前进程运行的用户名和所在组,工作目录为/
drop_privileges(conf.get('user', 'swift'))
# Ensure the configuration and application can be loaded before proceeding.
#
global_conf = {'log_name': log_name}
if 'global_conf_callback' in kwargs:
kwargs['global_conf_callback'](conf, global_conf)
loadapp(conf_path, global_conf=global_conf)
# set utils.FALLOCATE_RESERVE if desired
reserve = int(conf.get('fallocate_reserve', 0))
if reserve > 0:
utils.FALLOCATE_RESERVE = reserve
# redirect errors to logger and close stdio 调用方法capture_stdio实现日志记录未处理的异常,关闭标准输入输出,获取标准输出和异常信息的功能;
#输入输出重定向改向日志记录进行输出
capture_stdio(logger)
worker_count = config_auto_int_value(conf.get('workers'), CPU_COUNT)#获得CPU数目,或者默认为1
# Useful for profiling [no forks].
if worker_count == 0:
run_server(conf, logger, sock, global_conf=global_conf)
return 0
def kill_children(*args):
"""Kills the entire process group."""
logger.error('SIGTERM received')
signal.signal(signal.SIGTERM, signal.SIG_IGN)
running[0] = False
os.killpg(0, signal.SIGTERM)
def hup(*args):
"""Shuts down the server, but allows running requests to complete"""
logger.error('SIGHUP received')
signal.signal(signal.SIGHUP, signal.SIG_IGN)
running[0] = False
running = [True]
signal.signal(signal.SIGTERM, kill_children)
signal.signal(signal.SIGHUP, hup)
children = []
#开启worker_count个进程,每个进程都有一个wscgi,每个wscgi的最大连接数默认是1000
while running[0]:
while len(children) < worker_count:
pid = os.fork()
if pid == 0:
signal.signal(signal.SIGHUP, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
#开始运行wsgi和eventlet
run_server(conf, logger, sock)
logger.notice('Child %d exiting normally' % os.getpid())
return 0
else:
logger.notice('Started child %s' % pid)
children.append(pid)
try:
pid, status = os.wait()
if os.WIFEXITED(status) or os.WIFSIGNALED(status):
logger.error('Removing dead child %s' % pid)
children.remove(pid)
except OSError as err:
if err.errno not in (errno.EINTR, errno.ECHILD):
raise
except KeyboardInterrupt:
logger.notice('User quit')
break
greenio.shutdown_safe(sock)
sock.close()
logger.notice('Exited')
return 0
现在说下get_socket函数,
def get_socket(conf):
"""Bind socket to bind ip:port in conf
:param conf: Configuration dict to read settings from,根据配置文件进行地质端口的绑定,返回套接字
:returns : a socket object as returned from socket.listen or
ssl.wrap_socket if conf specifies cert_file
"""
try:
bind_port = int(conf['bind_port'])#获得/etc/swift/proxy-server.conf文件中的proxy-server节下的bind_port的内容
except (ValueError, KeyError, TypeError):
raise ConfigFilePortError()
bind_addr = (conf.get('bind_ip', '0.0.0.0'), bind_port)#获得/etc/swift/proxy-server.conf文件中的proxy-server节下的bind_ip的内容如果没有则返回0.0.0.0
address_family = [addr[0] for addr in socket.getaddrinfo(
bind_addr[0], bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM)
if addr[0] in (socket.AF_INET, socket.AF_INET6)][0]
sock = None
bind_timeout = int(conf.get('bind_timeout', 30))#获得/etc/swift/proxy-server.conf文件中的bind_timeout的值,如果 没有则返回30
retry_until = time.time() + bind_timeout#得出下次尝试时间
warn_ssl = False
while not sock and time.time() < retry_until:
try:
sock = listen(bind_addr, backlog=int(conf.get('backlog', 4096)),#获得/etc/swift/proxy-server.conf文件中的backlog的值,如果 没有则返回4096
family=address_family)
if 'cert_file' in conf:
warn_ssl = True
sock = ssl.wrap_socket(sock, certfile=conf['cert_file'],
keyfile=conf['key_file'])
except socket.error as err:
if err.args[0] != errno.EADDRINUSE:
raise
sleep(0.1)
if not sock:
raise Exception(_('Could not bind to %s:%s '
'after trying for %s seconds') % (
bind_addr[0], bind_addr[1], bind_timeout))
#设置socket属性
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# in my experience, sockets can hang around forever without keepalive
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
if hasattr(socket, 'TCP_KEEPIDLE'):
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 600)
if warn_ssl:
ssl_warning_message = _('WARNING: SSL should only be enabled for '
'testing purposes. Use external SSL '
'termination for a production deployment.')
get_logger(conf).warning(ssl_warning_message)
print(ssl_warning_message)
return sock
接下来是进行drop_privileges其主要作用就是根据配置文件进行运行目录的用户ID和组ID的更换,同时改变进程的运行目录,不过为啥?
def drop_privileges(user):
"""
Sets the userid/groupid of the current process, get session leader, etc.
:param user: User name to change privileges to
"""
if os.geteuid() == 0:
groups = [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
os.setgroups(groups)
#getpwnam获得对应uid的信息
user = pwd.getpwnam(user)
os.setgid(user[3])
os.setuid(user[2])
os.environ['HOME'] = user[5]
try:
os.setsid()
except OSError:
pass
os.chdir('/') # in case you need to rmdir on where you started the daemon设定当前运行目录/
os.umask(0o22) # ensure files are created with the correct privileges,设定当前运行权限
接下来是worker_count的设定,个人理解是进程数目的设定,要么是根据配置文件中的workers进行设定,要么是获得当前服务器的CPU的数目,(类似Nginx啊),接下来就是根据设定的进程数目,开启wsgi服务的数量,接下来最主要的就是run_server函数,它开启了wsgi和eventlet服务
def run_server(conf, logger, sock, global_conf=None):
# Ensure TZ environment variable exists to avoid stat('/etc/localtime') on
# some platforms. This locks in reported times to the timezone in which
# the server first starts running in locations that periodically change
# timezones.
os.environ['TZ'] = time.strftime("%z", time.gmtime())
wsgi.HttpProtocol.default_request_version = "HTTP/1.0"
# Turn off logging requests by the underlying WSGI software.
wsgi.HttpProtocol.log_request = lambda *a: None
# Redirect logging other messages by the underlying WSGI software.
wsgi.HttpProtocol.log_message = \
lambda s, f, *a: logger.error('ERROR WSGI: ' + f % a)
wsgi.WRITE_TIMEOUT = int(conf.get('client_timeout') or 60)
eventlet.hubs.use_hub(get_hub())
eventlet.patcher.monkey_patch(all=False, socket=True)
eventlet_debug = config_true_value(conf.get('eventlet_debug', 'no'))
eventlet.debug.hub_exceptions(eventlet_debug)
wsgi_logger = NullLogger()
if eventlet_debug:
# let eventlet.wsgi.server log to stderr
wsgi_logger = None
# utils.LogAdapter stashes name in server; fallback on unadapted loggers
if not global_conf:
if hasattr(logger, 'server'):
log_name = logger.server
else:
log_name = logger.name
global_conf = {'log_name': log_name}
app = loadapp(conf['__file__'], global_conf=global_conf)
#初始化最大连接数默认1024
max_clients = int(conf.get('max_clients', '1024'))
pool = RestrictedGreenPool(size=max_clients)
try:
# Disable capitalizing headers in Eventlet if possible. This is
# necessary for the AWS SDK to work with swift3 middleware.
argspec = inspect.getargspec(wsgi.server)
if 'capitalize_response_headers' in argspec.args:
wsgi.server(sock, app, wsgi_logger, custom_pool=pool,
capitalize_response_headers=False)
else:
wsgi.server(sock, app, wsgi_logger, custom_pool=pool)
except socket.error as err:
if err[0] != errno.EINVAL:
raise
pool.waitall()#等待所有进程执行完毕
设定wsgi 和eventlet的参数,然后开启服务,最后等待所有线程执行完毕,即可返回
greenio.shutdown_safe(sock)
sock.close()
logger.notice('Exited')
return 0
最后退出操作,至此proxy-server顺利开启