openstack-nova-Scheduler调度器学习
转载自:http://blog.lightcloud.cn/?p=123#comment-124Scheduler调度器Scheduler是调度服务器,为虚拟机分配节点。Scheduler.api提供了其他服务调用scheduler的接口。调用会通过rabbit-MQ传递到SchedulerManger。一、调度器的启动1. Scheduler由脚本 nov
转载自:http://blog.lightcloud.cn/?p=123#comment-124
Scheduler调度器
Scheduler是调度服务器,为虚拟机分配节点。
Scheduler.api提供了其他服务调用scheduler的接口。调用会通过rabbit-MQ传递到SchedulerManger。
一、调度器的启动
1. Scheduler由脚本 nova/bin/nova-scheduler启动。
怎么创建并启动一个服务:
1
2
3
4
5
6
7
8
|
utils.default_flagfile()
#检查是否带有配置文件,如果没有则用默认配置文件
/
etc
/
nova
/
nova.conf
flags.FLAGS(sys.argv)
#把启动脚本时带的配置参数加到flags中,flags保存了所有配置信息
logging.setup()
#日志模块
utils.monkey_patch()
server
=
service.Service.create(binary
=
'nova-scheduler'
)
#创建一个服务
service.serve(server)
#启动服务
service.wait()
#等到请求
|
可以看到启动一个服务先用service.Service.create()来创建一个Server对象,然后调用server和wait就可以了。
创建Server对象时只传了一个binary参数, binary是一个字符串 ”nova-scheduler”,创建什么服务就是根据这个字符串识别的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@classmethod
def
create(
cls
, host
=
None
, binary
=
None
, topic
=
None
, manager
=
None
,
report_interval
=
None
, periodic_interval
=
None
):
if
not
host:
host
=
FLAGS.host
if
not
binary:
binary
=
os.path.basename(inspect.stack()[
-
1
][
1
])
if
not
topic:
topic
=
binary.rpartition(
'nova-'
)[
2
]
if
not
manager:
manager
=
FLAGS.get(
'%s_manager'
%
topic,
None
)
if
not
report_interval:
report_interval
=
FLAGS.report_interval
if
not
periodic_interval:
periodic_interval
=
FLAGS.periodic_interval
service_obj
=
cls
(host, binary, topic, manager,
report_interval, periodic_interval)
return
service_obj
|
如果没有指定manager,则manager由topic连接上”_manager”来指定manager的名字,这个manager就是一个服务接收请求,处理请求的部分,是服务的关键部分。
未指定topic时,由binary去掉开头的”nova-“ 生成。所有创建scheduler服务器时manager 为 scheduler_manager,这时就会从flags中搜索scheduler_manager所对应的类名,来生成server对象。
创建的server有个manager属性,指向服务对应的manager,由前面的很容易知道server.manager指向SchedulerManager对象。
1
2
3
4
5
6
7
8
|
def
__init__(
self
, host, binary, topic, manager, report_interval
=
None
,
periodic_interval
=
None
,
*
args,
*
*
kwargs):
self
.host
=
host
self
.binary
=
binary
self
.topic
=
topic
self
.manager_class_name
=
manager
manager_class
=
utils.import_class(
self
.manager_class_name)
self
.manager
=
manager_class(host
=
self
.host,
*
args,
*
*
kwargs)
|
再来看看service.serve(server)是怎么执行的
1
2
3
4
5
6
|
def
serve(
*
servers):
global
_launcher
if
not
_launcher:
_launcher
=
Launcher()
for
server
in
servers:
_launcher.launch_server(server)
|
就是调用Launcher().launch_server(server)
1
2
3
|
def
launch_server(
self
, server):
gt
=
eventlet.spawn(
self
.run_server, server)
self
._services.append(gt)
|
二、SchedulerManager类
1
2
3
4
5
|
def
__init__(
self
, scheduler_driver
=
None
,
*
args,
*
*
kwargs):
if
not
scheduler_driver:
scheduler_driver
=
FLAGS.scheduler_driver
self
.driver
=
utils.import_object(scheduler_driver)
super
(SchedulerManager,
self
).__init__(
*
args,
*
*
kwargs)
|
driver属性默认指向scheduler.multi.MultiScheduler对象。
在SchedulerManager中有方法
1
2
3
4
|
def
__getattr__(
self
, key):
"""Converts all method calls to use the schedule method
调用未显式定义的方法时转成偏函数"""
return
functools.partial(
self
._schedule, key)
|
对于未在SchedulerManager中显式定义的方法,返回_schedule方法并绑定调用的方法名。
显示定义的方法会直接调用。
现以run_instance请求为例。
在接收到启动虚拟机请求时,SchedulerManager.run_instance被调用
1
2
3
|
def
run_instance(
self
, context, topic,
*
args,
*
*
kwargs):
args
=
(context,)
+
args
return
self
.driver.schedule_run_instance(
*
args,
*
*
kwargs)
|
转到MultiScheduler.scheduler_run_instance方法
MultiScheduler.scheduler_run_instance定义如下:
1
2
|
def
schedule_run_instance(
self
,
*
args,
*
*
kwargs):
return
self
.drivers[
'compute'
].schedule_run_instance(
*
args,
*
*
kwargs)
|
其中MultiScheduler.drivers为
1
2
|
self
.drivers
=
{
'compute'
: filter_scheduler.FilterScheduler(),
'volume'
: chance.ChanceScheduler() }
|
所对计算任务请求是转到FilterScheduler类来处理,对于卷的请求是由ChanceScheduler类处理。
最后对启动虚拟机的任务由FilterScheduler.schedule_run_instance来处理。
三、调度算法
1.得到权重和计算成本的函数列表:(FilterScheduler. get_cost_functions)
i. 每个topic对应一个权重和计算成本的列表,如果之前已经缓存过,就直接返回
ii. 获得所有权重和计算成本的函数列表,缓存下来,然后返回。(计算成本的函数是” least_cost_functions”对应的,默认是只有compute_fill_first_cost_fn,定义如下:
1
2
|
def
compute_fill_first_cost_fn(host_state, weighing_properties):
return
host_state.free_ram_mb
|
就是返回剩余的内在大小
每个计算成本的函数对就一个权重因子,是在flag中定义,名字为函数名加”_weight”。
compute_fill_first_cost_fn 对应的权重因子为compute_fill_first_cost_fn_weight。
在D版中为 1.0,在Essex版中为-1.0。
即选择节点的优先级仅是按剩余内存大小来处理的,在D版是剩余内存越小,优先级越高;而在Essex版是剩余内存越大,优先级越高,这应该是D版的一个bug,在Essex版得到修改。
计算成本的函数和对应的权重因子可以在/etc/nova/nova.conf中配置:
可以用逗号分隔多个计算函数
1
2
3
|
least_cost_functions=nova.scheduler.least_cost.compute_fill_first_cost_fn,nova.scheduler.least_cost.my_cost_fn
compute_fill_first_cost_fn_weight=1.0
my_cost_fn_weight=0.5
|
2. 得到所有可用的未过滤的节点信息(HostManager. get_all_host_states)
i. 首先会从数据库中选出所有可用的未过滤的节点组成的一个字典host_state_map。
ii. 所有的计算节点都保存在nova库的coupute_nodes表中。
iii. 从表中取出所有节点必要的信息(如节点的内存容量,虚拟CPU个数,硬盘容量等),放到字典host_state_map中
iv. 从数据库表nova.instances中取出所有实例instance的信息。
v. 根据instance所在的主机,从host_state_map中对应主机减去实例所占用的资源,得到主机的剩余资源
3. 根据定义的过滤方法过滤掉不合适的主机(HostManager. filter_hosts)
i. 默认过滤方法为
‘AvailabilityZoneFilter’,
‘RamFilter’,
‘ComputeFilter’
三个类,在flag中scheduler_default_filters定义
过滤方法对应的类都是继承自scheduler.filters.BaseHostFilter类,只要实现了host_passes方法就可以实现对主机的过滤,返回真就是这个主机符合条件,返回假就是不符合条件,被过滤掉。
以RamFilter为例:
1
2
3
4
5
6
7
8
9
|
class
RamFilter(filters.BaseHostFilter):
"""Ram Filter with over subscription flag"""
def
host_passes(
self
, host_state, filter_properties):
"""Only return hosts with sufficient available RAM."""
instance_type
=
filter_properties.get(
'instance_type'
)
requested_ram
=
instance_type[
'memory_mb'
]
free_ram_mb
=
host_state.free_ram_mb
return
free_ram_mb
*
FLAGS.ram_allocation_ratio >
=
requested_ram
|
只是判断了主机剩余内存乘以内存分配比率大于申请内在,就通过本次过滤,至于能不能申请还要看其他过滤条件,有一个条件不成立就会被过滤掉。
也可以在nova.conf中定义过滤方法:
1
2
3
4
|
scheduler_available_filters定义可用的过滤器,可以多次定义,每个scheduler_driver=nova.scheduler.distributed_scheduler.FilterScheduler
scheduler_available_filters=nova.scheduler.filters.standard_filters
scheduler_available_filters=myfilter.MyFilter
scheduler_default_filters=RamFilter,ComputeFilter,MyFilter
|
4. 根据计算成本函数和对应权重计算最适合主机:
i. 在least_cost.weight_sum计算
ii. 根据成本计算函数列表生成一个矩阵(网格),
iii. 每行为一个计算函数对所有主机的计算结果,即每列对应一个主机通过所有函数的成本计算结果(此处和代码中英文注释不同,疑注释有误);
iv. 每列为一个主机通过各函数成本计算结果,加起来为主机总的成本,得到所有主机总的成本。
v. 成本最低的为最优主机,被选出来
更多推荐
所有评论(0)