<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">今天要完成:</span>
1. nova api是如何创建wsgi服务的?为什么一个.../v2/{tanent_id}/server/{server_id}的处理方法和.../v2/{tenant_id}/servers/{server_id}/metadata的处理方法就不一样呢?
2. nova api到底监听了几个端口,有几个wsgi服务?
现象:
[root@compute-57-09 admin]# ps -ef|grep nova
root 10298 10105 1 Sep09 pts/6 07:28:09 /usr/bin/python /usr/bin/nova-api
root 10333 10116 0 Sep09 pts/17 00:23:36 /usr/bin/python /usr/bin/nova-consoleauth --config-file /etc/nova/nova.conf
root 10338 10113 0 Sep09 pts/14 00:23:00 /usr/bin/python /usr/bin/nova-cert --config-file /etc/nova/nova.conf
root 10339 10114 0 Sep09 pts/15 00:30:05 /usr/bin/python /usr/bin/nova-scheduler --config-file /etc/nova/nova.conf
root 10344 10117 0 Sep09 pts/18 00:00:04 /usr/bin/python /usr/bin/nova-objectstore --config-file /etc/nova/nova.conf
root 10346 10115 0 Sep09 pts/16 00:16:25 /usr/bin/python /usr/bin/nova-novncproxy --config-file /etc/nova/nova.conf --web /opt/stack/noVNC
root 10347 10112 1 Sep09 pts/13 07:20:57 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10628 10347 1 Sep09 pts/13 12:40:59 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10629 10347 1 Sep09 pts/13 12:40:49 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10630 10347 1 Sep09 pts/13 12:40:41 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10631 10347 1 Sep09 pts/13 12:41:08 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10632 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10633 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10634 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10635 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10658 10298 0 Sep09 pts/6 00:40:07 /usr/bin/python /usr/bin/nova-api
root 10659 10298 0 Sep09 pts/6 00:41:20 /usr/bin/python /usr/bin/nova-api
root 10660 10298 0 Sep09 pts/6 00:52:23 /usr/bin/python /usr/bin/nova-api
root 10661 10298 0 Sep09 pts/6 00:45:19 /usr/bin/python /usr/bin/nova-api
root 10666 10298 0 Sep09 pts/6 00:00:06 /usr/bin/python /usr/bin/nova-api
root 10667 10298 0 Sep09 pts/6 00:00:09 /usr/bin/python /usr/bin/nova-api
root 10668 10298 0 Sep09 pts/6 00:00:10 /usr/bin/python /usr/bin/nova-api
root 10669 10298 0 Sep09 pts/6 00:00:08 /usr/bin/python /usr/bin/nova-api
root 24157 10346 0 Oct08 pts/16 00:00:00 [nova-novncproxy] <defunct>
root 24499 17151 0 09:40 pts/0 00:00:00 grep nova
说明,nova-api很多,但是有一个父进程,就是最上面的那个,其他都是它派生出来的;
[root@compute-57-09 admin]# cat /usr/bin/nova-api
#!/usr/bin/python
# PBR Generated from u'console_scripts'
import sys
from nova.cmd.api import main
if __name__ == "__main__":
sys.exit(main())
nova.cmd.api的代码如下:
def main():
config.parse_args(sys.argv)
logging.setup("nova")
utils.monkey_patch()
objects.register_all()
gmr.TextGuruMeditation.setup_autorun(version)
launcher = service.process_launcher()
for api in CONF.enabled_apis:
should_use_ssl = api in CONF.enabled_ssl_apis
if api == 'ec2':
server = service.WSGIService(api, use_ssl=should_use_ssl,
max_url_len=16384)
else:
server = service.WSGIService(api, use_ssl=should_use_ssl)
launcher.launch_service(server, workers=server.workers or 1)
launcher.wait()
1)是否nova-api一启动就是那多么个进程?
应该是的,我停止nova-api服务,又启动服务;发现直接多了好多
stack 781 11718 14 09:48 pts/7 00:00:03 /usr/bin/python /usr/bin/nova-api
stack 790 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 791 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 792 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 793 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 797 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 798 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 799 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 800 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 807 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 808 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 809 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
stack 810 781 0 09:48 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
a)会不会执行一条nova命令就会多出来一个nova-api 呢?
通过实验并没有多出来一个!说明,每个nova-api都各司其职,执行不同的代码。
b)如何知道每个nova-api监听的端口?
[root@compute-57-09 admin]# ps -ef|grep nova
root 8960 17151 0 10:05 pts/0 00:00:00 grep nova
root 10298 10105 1 Sep09 pts/6 07:28:26 /usr/bin/python /usr/bin/nova-api
root 10333 10116 0 Sep09 pts/17 00:23:36 /usr/bin/python /usr/bin/nova-consoleauth --config-file /etc/nova/nova.conf
root 10338 10113 0 Sep09 pts/14 00:23:01 /usr/bin/python /usr/bin/nova-cert --config-file /etc/nova/nova.conf
root 10339 10114 0 Sep09 pts/15 00:30:06 /usr/bin/python /usr/bin/nova-scheduler --config-file /etc/nova/nova.conf
root 10344 10117 0 Sep09 pts/18 00:00:04 /usr/bin/python /usr/bin/nova-objectstore --config-file /etc/nova/nova.conf
root 10346 10115 0 Sep09 pts/16 00:16:26 /usr/bin/python /usr/bin/nova-novncproxy --config-file /etc/nova/nova.conf --web /opt/stack/noVNC
root 10347 10112 1 Sep09 pts/13 07:21:13 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10628 10347 1 Sep09 pts/13 12:41:26 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10629 10347 1 Sep09 pts/13 12:41:16 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10630 10347 1 Sep09 pts/13 12:41:08 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10631 10347 1 Sep09 pts/13 12:41:35 /usr/bin/python /usr/bin/nova-conductor --config-file /etc/nova/nova.conf
root 10632 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10633 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10634 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10635 10298 0 Sep09 pts/6 00:00:02 /usr/bin/python /usr/bin/nova-api
root 10658 10298 0 Sep09 pts/6 00:40:07 /usr/bin/python /usr/bin/nova-api
root 10659 10298 0 Sep09 pts/6 00:41:20 /usr/bin/python /usr/bin/nova-api
root 10660 10298 0 Sep09 pts/6 00:52:23 /usr/bin/python /usr/bin/nova-api
root 10661 10298 0 Sep09 pts/6 00:45:20 /usr/bin/python /usr/bin/nova-api
root 10666 10298 0 Sep09 pts/6 00:00:06 /usr/bin/python /usr/bin/nova-api
root 10667 10298 0 Sep09 pts/6 00:00:09 /usr/bin/python /usr/bin/nova-api
root 10668 10298 0 Sep09 pts/6 00:00:10 /usr/bin/python /usr/bin/nova-api
root 10669 10298 0 Sep09 pts/6 00:00:08 /usr/bin/python /usr/bin/nova-api
root 24157 10346 0 Oct08 pts/16 00:00:00 [nova-novncproxy] <defunct>
[root@compute-57-09 admin]# netstat -anlp | grep 10298
tcp 0 0 0.0.0.0:8773 0.0.0.0:* LISTEN 10298/python
tcp 0 0 0.0.0.0:8774 0.0.0.0:* LISTEN 10298/python
tcp 0 0 0.0.0.0:8775 0.0.0.0:* LISTEN 10298/python
看看8773 8774 8775都是干什么的?
网上说的很清楚:Nova-api 8773 (for EC2 API) 8774 (for openstack API) 8775 (metadata port) cinder 8776
[root@compute-57-09 admin]# netstat -anp | grep 10632
[root@compute-57-09 admin]# netstat -anp | grep 10633
[root@compute-57-09 admin]# netstat -anp | grep 10634
[root@compute-57-09 admin]# netstat -anp | grep 10635
[root@compute-57-09 admin]# netstat -anp | grep 10658
tcp 0 0 192.168.39.30:8774 172.16.207.68:60072 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:55861 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56512 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52688 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60042 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51513 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51742 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56662 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52576 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51940 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52694 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:53572 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56622 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:58098 192.168.39.30:5672 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56688 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52813 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:55874 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56692 ESTABLISHED 10658/python
tcp 1 0 192.168.39.30:43471 192.168.39.190:3306 CLOSE_WAIT 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56652 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52792 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52554 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52786 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 192.168.39.30:35358 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:53564 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51726 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56491 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56479 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:55990 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56473 ESTABLISHED 10658/python
tcp 1 0 192.168.39.30:43470 192.168.39.190:3306 CLOSE_WAIT 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:53630 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51495 ESTABLISHED 10658/python
tcp 1 0 192.168.39.30:43473 192.168.39.190:3306 CLOSE_WAIT 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:55680 ESTABLISHED 10658/python
tcp 1 0 192.168.39.30:43476 192.168.39.190:3306 CLOSE_WAIT 10658/python
tcp 1 0 192.168.39.30:43472 192.168.39.190:3306 CLOSE_WAIT 10658/python
tcp 0 0 192.168.39.30:57190 192.168.39.30:5672 ESTABLISHED 10658/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56527 ESTABLISHED 10658/python
[root@compute-57-09 admin]# netstat -anp | grep 10659
tcp 0 0 192.168.39.30:8774 172.16.207.68:60795 ESTABLISHED 10659/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:63898 ESTABLISHED 10659/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51432 ESTABLISHED 10659/python
tcp 0 0 192.168.39.30:57477 192.168.39.30:5672 ESTABLISHED 10659/python
tcp 1 0 192.168.39.30:43450 192.168.39.190:3306 CLOSE_WAIT 10659/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:53701 ESTABLISHED 10659/python
tcp 1 0 192.168.39.30:43451 192.168.39.190:3306 CLOSE_WAIT 10659/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60117 ESTABLISHED 10659/python
tcp 0 0 192.168.39.30:45147 192.168.39.30:5672 ESTABLISHED 10659/python
tcp 1 0 192.168.39.30:43448 192.168.39.190:3306 CLOSE_WAIT 10659/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51474 ESTABLISHED 10659/python
tcp 1 0 192.168.39.30:43449 192.168.39.190:3306 CLOSE_WAIT 10659/python
tcp 0 0 192.168.39.30:57226 192.168.39.30:5672 ESTABLISHED 10659/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60879 ESTABLISHED 10659/python
tcp 1 0 192.168.39.30:43455 192.168.39.190:3306 CLOSE_WAIT 10659/python
[root@compute-57-09 admin]# netstat -anp | grep 10660
tcp 0 0 192.168.39.30:8774 172.16.207.68:53982 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51424 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:50736 192.168.39.30:5672 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:57846 192.168.39.30:5672 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52178 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:62032 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:57245 192.168.39.30:5672 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52220 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52414 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60074 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52234 ESTABLISHED 10660/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:52402 ESTABLISHED 10660/python
[root@compute-57-09 admin]# netstat -anp | grep 10661
tcp 0 0 192.168.39.30:8774 172.16.207.68:53641 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60888 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60957 ESTABLISHED 10661/python
tcp 1 0 192.168.39.30:43465 192.168.39.190:3306 CLOSE_WAIT 10661/python
tcp 1 0 192.168.39.30:43461 192.168.39.190:3306 CLOSE_WAIT 10661/python
tcp 0 0 192.168.39.30:47976 192.168.39.30:5672 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:57672 192.168.39.30:5672 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:51946 ESTABLISHED 10661/python
tcp 1 0 192.168.39.30:43459 192.168.39.190:3306 CLOSE_WAIT 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:56618 ESTABLISHED 10661/python
tcp 1 0 192.168.39.30:43460 192.168.39.190:3306 CLOSE_WAIT 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:63924 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:57233 192.168.39.30:5672 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60964 ESTABLISHED 10661/python
tcp 1 0 192.168.39.30:43462 192.168.39.190:3306 CLOSE_WAIT 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:55826 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60803 ESTABLISHED 10661/python
tcp 0 0 192.168.39.30:8774 172.16.207.68:60633 ESTABLISHED 10661/python
[root@compute-57-09 admin]# netstat -anp | grep 10667
tcp 0 0 192.168.39.30:58746 192.168.39.30:5672 ESTABLISHED 10667/python
tcp 0 0 192.168.39.30:58744 192.168.39.30:5672 ESTABLISHED 10667/python
[root@compute-57-09 admin]# netstat -anp | grep 10666
tcp 0 0 192.168.39.30:58553 192.168.39.30:5672 ESTABLISHED 10666/python
tcp 0 0 192.168.39.30:58551 192.168.39.30:5672 ESTABLISHED 10666/python
[root@compute-57-09 admin]# netstat -anp | grep 10668
tcp 0 0 192.168.39.30:55172 192.168.39.30:5672 ESTABLISHED 10668/python
tcp 0 0 192.168.39.30:55171 192.168.39.30:5672 ESTABLISHED 10668/python
[root@compute-57-09 admin]# netstat -anp | grep 10669
tcp 0 0 192.168.39.30:55117 192.168.39.30:5672 ESTABLISHED 10669/python
tcp 0 0 192.168.39.30:55119 192.168.39.30:5672 ESTABLISHED 10669/python
反复出现:5672,rabbit_port = 5672
3306,mysql
ec2的接口没人访问,还有metadata的接口没人访问,我在虚机中访问169.254.169.254,这样应该可以建立8775连接
[root@BC-EC-85-50 ~]# netstat -anp|grep 5188
tcp 0 0 192.168.85.50:44063 192.168.85.50:5672 ESTABLISHED 5188/python
tcp 1 0 192.168.85.50:52381 192.168.85.50:3306 CLOSE_WAIT 5188/python
tcp 0 0 192.168.85.50:44064 192.168.85.50:5672 ESTABLISHED 5188/python
tcp 0 0 192.168.85.50:8774 192.168.85.50:40955 ESTABLISHED 5188/python
tcp 0 0 192.168.85.50:8776 192.168.85.50:51881 ESTABLISHED 25175/python
tcp 0 0 ::ffff:192.168.85.50:51881 ::ffff:192.168.85.50:8776 ESTABLISHED 3821/java
通过在虚机中不断的
curl 169.254.169.254:80/openstack/latest/meta_data.json
在metadata server所在的机器上确实能够看到访问8775的连接:
tcp 0 0 192.168.85.50:34924 192.168.85.50:8775 TIME_WAIT -
tcp 0 0 192.168.85.50:34461 192.168.85.50:8775 TIME_WAIT -
tcp 0 0 192.168.85.50:34980 192.168.85.50:8775 TIME_WAIT -
tcp 0 0 192.168.85.50:34664 192.168.85.50:8775 TIME_WAIT -
tcp 0 0 192.168.85.50:34578 192.168.85.50:8775 TIME_WAIT -
可以大胆推测下,这个就是neutron-metadata-agent向nova meta_data server请求数据所建立的socket连接
C.nova-api不一定要监听端口,监听端口的nova-api只有一个,那就是所有nova-api的父进程,他负责监听端口,具体的通信交给它的孩子们。
D.一个python程序是否能监听多个端口?
应该可以,创建好几个socket,并监听就行
E.子nova-api每一个有什么作用呢?
貌似是nova-api代码中有好几个os_fork(),这样就创建了好几个新的进程,那么具体是干什么的呢?还得分析下代码,而且应该还能调试,good
代码中,首先启动ec2 server:
日志:
2014-10-09 11:01:51.482 INFO nova.openstack.common.service [-] Starting 4 workers
2014-10-09 11:01:51.486 INFO nova.openstack.common.service [-] Started child 5595
2014-10-09 11:01:51.492 INFO nova.openstack.common.service [-] Started child 5597
2014-10-09 11:01:51.498 INFO nova.openstack.common.service [-] Started child 5601
2014-10-09 11:01:51.503 INFO nova.openstack.common.service [-] Started child 5602
这个debug信息显示出,ec2有4个工作进程,大胆推断,一共有13个nova-api,因此,metadata,openstack,ec2,各有4个工作进程,我想应该是这样的
<span style="color: rgb(84, 84, 84); font-family: arial, sans-serif;font-size:12px; line-height: 18.2000007629395px;">再看日志,说明,每个进程都会启动一个wsgi的服务,去进行服务</span>
2014-10-09 11:01:51.604 INFO nova.ec2.wsgi.server [-] (5595) wsgi starting up on http://0.0.0.0:8773/
2014-10-09 11:01:51.614 INFO nova.ec2.wsgi.server [-] (5597) wsgi starting up on http://0.0.0.0:8773/
2014-10-09 11:01:51.625 INFO nova.ec2.wsgi.server [-] (5602) wsgi starting up on http://0.0.0.0:8773/
2014-10-09 11:01:51.623 INFO nova.ec2.wsgi.server [-] (5601) wsgi starting up on http://0.0.0.0:8773/
果然被言重:openstack的api也创建4个工作进程
2014-10-09 11:13:11.161 INFO nova.wsgi [-] osapi_compute listening on 0.0.0.0:8774
2014-10-09 11:13:11.161 INFO nova.openstack.common.service [-] Starting 4 workers
2014-10-09 11:13:11.164 INFO nova.openstack.common.service [-] Started child 6457
2014-10-09 11:13:11.168 INFO nova.openstack.common.service [-] Started child 6458
2014-10-09 11:13:11.170 INFO nova.osapi_compute.wsgi.server [-] (6457) wsgi starting up on http://0.0.0.0:8774/
2014-10-09 11:13:11.172 INFO nova.openstack.common.service [-] Started child 6459
2014-10-09 11:13:11.178 INFO nova.osapi_compute.wsgi.server [-] (6459) wsgi starting up on http://0.0.0.0:8774/
2014-10-09 11:13:11.179 INFO nova.osapi_compute.wsgi.server [-] (6458) wsgi starting up on http://0.0.0.0:8774/
2014-10-09 11:13:11.175 INFO nova.openstack.common.service [-] Started child 6460
2014-10-09 11:13:11.180 INFO nova.osapi_compute.wsgi.server [-] (6460) wsgi starting up on http://0.0.0.0:8774/
metadata api也创建4个工作进程
2014-10-09 11:13:11.220 INFO nova.wsgi [-] metadata listening on 0.0.0.0:8775
2014-10-09 11:13:11.221 INFO nova.openstack.common.service [-] Starting 4 workers
2014-10-09 11:13:11.224 INFO nova.openstack.common.service [-] Started child 6463
2014-10-09 11:13:11.227 INFO nova.openstack.common.service [-] Started child 6464
2014-10-09 11:13:11.231 INFO nova.openstack.common.service [-] Started child 6465
2014-10-09 11:13:11.238 INFO nova.metadata.wsgi.server [-] (6464) wsgi starting up on http://0.0.0.0:8775/
2014-10-09 11:13:11.239 INFO nova.metadata.wsgi.server [-] (6463) wsgi starting up on http://0.0.0.0:8775/
2014-10-09 11:13:11.235 INFO nova.openstack.common.service [-] Started child 6466
看代码:
def main():
config.parse_args(sys.argv)
logging.setup("nova")
utils.monkey_patch()
objects.register_all()
gmr.TextGuruMeditation.setup_autorun(version)
launcher = service.process_launcher()
for api in CONF.enabled_apis:
should_use_ssl = api in CONF.enabled_ssl_apis
if api == 'ec2':
server = service.WSGIService(api, use_ssl=should_use_ssl,
max_url_len=16384)
else:
server = service.WSGIService(api, use_ssl=should_use_ssl)
launcher.launch_service(server, workers=server.workers or 1)
launcher.wait()
launcher是service.process_launcher()返回的,因此launcher.launch_service也是执行的/nova/openstack/common/service.py中的launch_serivice()
def launch_service(self, service, workers=1):
#ServiceWrapper不知道是干什么的。。。
<span style="white-space:pre"> </span>wrap = ServiceWrapper(service, workers)
<span style="white-space:pre"> </span>#wrap.workers = 4
LOG.info(_LI('Starting %d workers'), wrap.workers)
#循环4次,执行4次!start_child
<span style="white-space:pre"> </span>while self.running and len(wrap.children) < wrap.workers:
self._start_child(wrap)
看下_start_child(wrap)的代码:
def _start_child(self, wrap):
if len(wrap.forktimes) > wrap.workers:
# Limit ourselves to one process a second (over the period of
# number of workers * 1 second). This will allow workers to
# start up quickly but ensure we don't fork off children that
# die instantly too quickly.
if time.time() - wrap.forktimes[0] < wrap.workers:
LOG.info(_LI('Forking too fast, sleeping'))
time.sleep(1)
wrap.forktimes.pop(0)
wrap.forktimes.append(time.time())
<span style="white-space:pre"> </span>#创建子进程了
pid = os.fork()
#pid==0 子进程
<span style="line-height: 18.2000007629395px; font-family: arial, sans-serif;"><span style="white-space:pre"> </span> if pid == 0:</span>
launcher = self._child_process(wrap.service)
while True:
self._child_process_handle_signal()
status, signo = self._child_wait_for_exit_or_signal(launcher)
if not _is_sighup_and_daemon(signo):
break
launcher.restart()
os._exit(status)
LOG.info(_LI('Started child %d'), pid)
wrap.children.add(pid)
self.children[pid] = wrap
return pid
上面最重要的是
launcher = self._child_process(wrap.service)
def _child_process(self, service):
self._child_process_handle_signal()
# Reopen the eventlet hub to make sure we don't share an epoll
# fd with parent and/or siblings, which would be bad
eventlet.hubs.use_hub()
# Close write to ensure only parent has it open
os.close(self.writepipe)
# Create greenthread to watch for parent to close pipe
eventlet.spawn_n(self._pipe_watcher)
# Reseed random number generator
random.seed()
<span style="white-space:pre"> </span>#下面的应该比较重要
launcher = Launcher()
launcher.launch_service(service)
return launcher
跟进launcher.launch_service(service)
def launch_service(self, service):
"""Load and start the given service.
:param service: The service you would like to start.
:returns: None
"""
service.backdoor_port = self.backdoor_port
self.services.add(service)
跟进self.services.add(service)
def add(self, service):
self.services.append(service)
self.tg.add_thread(self.run_service, service, self.done)
跟进self.tg.add_thread(self.run_service, service, self.done)
def add_thread(self, callback, *args, **kwargs):
gt = self.pool.spawn(callback, *args, **kwargs)
th = Thread(gt, self)
self.threads.append(th)
return th
这里的callback就是run_service,但是我对于Thread(),对于pool.spawn都不熟,但是,原理上应该是创建一个线程执行run_service,service作为run_server的参数也一同传进去了,metadata,openstack,ec2对应的service应该是不同的。
@staticmethod
def run_service(service, done):
"""Service start wrapper.
:param service: service to run
:param done: event to wait on until a shutdown is triggered
:returns: None
"""
service.start()
systemd.notify_once()
done.wait()
最终,果然进入了这个函数,调用的是service.start() nova/service.py
跟进service.start()
def start(self):
"""Start serving this service using loaded configuration.
Also, retrieve updated port number in case '0' was passed in, which
indicates a random port should be used.
:returns: None
"""
if self.manager:
self.manager.init_host()
self.manager.pre_start_hook()
if self.backdoor_port is not None:
self.manager.backdoor_port = self.backdoor_port
self.server.start()
if self.manager:
self.manager.post_start_hook()
跟进 self.server.start() nova/wsgi.py
def start(self):
"""Start serving a WSGI application.
:returns: None
"""
# The server socket object will be closed after server exits,
# but the underlying file descriptor will remain open, and will
# give bad file descriptor error. So duplicating the socket object,
# to keep file descriptor usable.
dup_socket = self._socket.dup()
if self._use_ssl:
try:
ca_file = CONF.ssl_ca_file
cert_file = CONF.ssl_cert_file
key_file = CONF.ssl_key_file
if cert_file and not os.path.exists(cert_file):
raise RuntimeError(
_("Unable to find cert_file : %s") % cert_file)
if ca_file and not os.path.exists(ca_file):
raise RuntimeError(
_("Unable to find ca_file : %s") % ca_file)
if key_file and not os.path.exists(key_file):
raise RuntimeError(
_("Unable to find key_file : %s") % key_file)
if self._use_ssl and (not cert_file or not key_file):
raise RuntimeError(
_("When running server in SSL mode, you must "
"specify both a cert_file and key_file "
"option value in your configuration file"))
ssl_kwargs = {
'server_side': True,
'certfile': cert_file,
'keyfile': key_file,
'cert_reqs': ssl.CERT_NONE,
}
if CONF.ssl_ca_file:
ssl_kwargs['ca_certs'] = ca_file
ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED
dup_socket = eventlet.wrap_ssl(dup_socket,
**ssl_kwargs)
dup_socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
# sockets can hang around forever without keepalive
dup_socket.setsockopt(socket.SOL_SOCKET,
socket.SO_KEEPALIVE, 1)
# This option isn't available in the OS X version of eventlet
if hasattr(socket, 'TCP_KEEPIDLE'):
dup_socket.setsockopt(socket.IPPROTO_TCP,
socket.TCP_KEEPIDLE,
CONF.tcp_keepidle)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error(_("Failed to start %(name)s on %(host)s"
":%(port)s with SSL support") % self.__dict__)
wsgi_kwargs = {
'func': eventlet.wsgi.server,
'sock': dup_socket,
'site': self.app,
'protocol': self._protocol,
'custom_pool': self._pool,
'log': self._wsgi_logger,
'log_format': CONF.wsgi_log_format,
'debug': False
}
if self._max_url_len:
wsgi_kwargs['url_length_limit'] = self._max_url_len
self._server = eventlet.spawn(**wsgi_kwargs)
最重要的是:self._server = eventlet.spawn(**wsgi_kwargs),但是wsgi_kwargs的参数非常重要;给出ec2的参数:
wsgi_kwargs = {
'func': eventlet.wsgi.server, <code object server at 0x255c378, file "/usr/lib/python2.6/site-packages/eventlet/wsgi.py", line 689>
'sock': dup_socket, <eventlet.greenio.GreenSocket object at 0x3950e50>
'site': self.app, URLMap: {(None, '/services/Cloud'): <nova.api.ec2.FaultWrapper object at 0x39506d0>}
'protocol': self._protocol, eventlet.wsgi.HttpProtocol
'custom_pool': self._pool, <eventlet.greenpool.GreenPool object at 0x2d55990>
'log': self._wsgi_logger, <nova.openstack.common.log.WritableLogger object at 0x2d55e10>
'log_format': CONF.wsgi_log_format, '%(client_ip)s "%(request_line)s" status: %(status_code)s len: %(body_length)s time: %(wall_seconds).7f'
'debug': False
}
看到这里的时候,必须要对eventlet进行一个彻底的分析,否则下面的代码是无法理解的,我们得从最基本的学起:
eventlet (http://www.choudan.net/2013/08/18/OpenStack-eventlet%E5%88%86%E6%9E%90(%E4%B8%80).html)
import greenlet
def test1(n):
print "test1:",n
gr2.switch(32)
print "test1: over"
def test2(n):
print "test2:",n
gr1.switch(23)
print "test2: over"
greenlet = greenlet.greenlet
current = greenlet.getcurrent()
gr1 = greenlet(test1,current)
gr2 = greenlet(test2,current)
gr1.switch(2)
这句话是精华,说明什么?执行
gr1 = greenlet(test1,current)
gr1得到了一个空堆栈,当执行到
gr1.switch(2)
他所指定的函数将被启动,大胆的猜测,执行到这句话时,执行将跳转到
def test1(n):
输出test1:2
执行
<pre name="code" class="python" style="color: rgb(84, 84, 84); line-height: 18.2000007629395px;"> gr2.switch(32)
会跳转到
def test2(n):
输出:
test2:32
执行
gr1.switch(23)
这句话是最重要的,它又调回test1刚才被打断的地方,也就是将执行
print "test1: over"
执行完了到哪去呢?不会再跳到test2了,只会退出!直接返回
gr1.switch(2)
然后退出,这个过程也很重要要理解
同理:再看一个修改的例子:
import greenlet
def test1(n):
print "test1:",n
gr2.switch(32)
print "test1: over"
def test2(n):
print "test2:",n
#gr1.switch(23)
print "test2: over"
greenlet = greenlet.greenlet
current = greenlet.getcurrent()
gr1 = greenlet(test1,current)
gr2 = greenlet(test2,current)
gr1.switch(2)
输出是:
test1: 2
test2: 32
test2: over
3.所谓的父greenlet
父greenlet是当greenlet死掉时,继续原来的位置执行
greenlet(run=None,parent=None)
创建一个greenlet对象,而不执行。run是执行回调,而parent是父greenlet,缺省是当前greenlet。
greenlet.getcurrent()
返回当前greenlet,也就是谁在调用这个函数。
greenlet.GreenletExit
5.几个greenlet之间的切换:这个特定的异常不会波及到父greenlet,它用于干掉一个greenlet。
import greenlet
def test1(x,y):
z=gr2.switch(x+y)
print z
def test2(u):
print u
gr1.switch(42)
greenlet = greenlet.greenlet
#current = greenlet.getcurrent()
gr1=greenlet(test1)
gr2=greenlet(test2)
gr1.switch("hello"," world")
注意一点,gr1.switch(42)将切换回test1的
z=gr2.switch(x+y)
z将被赋值为42,其他的复杂的内容我也说不清楚,例子就是这样,输出:
hello world
42
green thread
def process_commands(*args):
while True:
line=''
while not line.endswith('n'):
line+=read_next_char()
if line=='quitn':
print "are you sure?"
if read_next_char()!="y":
continue #忽略指令
process_commands(line)
这是个命令行分析处理的代码,read_next_char()可以获得用户的下一个输入,cli中应该很简单
解决方法1
def process_commands(*args):
主动调用
line+=read_next_char()
获得字母,而是按键被触发之后,进入相应的处理函数,将这个字母主动告诉process_commands,如果不用greenlet,我们先思考下,我们将怎样做?
<pre name="code" class="python" style="color: rgb(51, 51, 51); text-align: justify;">def process_commands(*args):
需要字母的输入时,它就切换到key_event(), 它自己被挂起了,如果没有用户输入,key_event()将挂起,有了之后,立刻切换到process_commands(),并且通过gr1.switch(参数)参数可以讲字母传回去,得到字母后,期待下一个字母,将再次切换到key_event(),可以说,完美的解决了这个问题。
def event_keydown(key):
g_processor.switch(key)
def read_next_char():
g_self=greenlet.getcurrent()
next_char=g_self.parent.switch() #跳到上一层(main)的greenlet,等待下一次按键
return next_char
g_processor=greenlet(process_commands)
g_processor.switch(*args)
gui.mainloop()
这段代码简短而精妙啊!
g_self=greenlet.getcurrent()
这个是在已经被切换的基础上执行的,因此已经是第二级了,通过调用g_self.parent,switch()能回到最上层的
g_processor.switch(*args)
之后继续执行,如果还看不懂,自己试验一下
2)CONF.enabled_apis有哪些?