找回密码
 注册
查看: 2242|回复: 0

Nova - evacuate疏散

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2021-7-27 12:00:06 | 显示全部楼层 |阅读模式
当实例所在的节点发生故障不可用时,可执行evacuate操作,在另外一个新节点rebuild该实例,实现高可用。' T, |; x# Q0 `2 ~$ Q' I" @6 P
这可以是OpenStack计算节点HA的一种实现方案。
# D* H' s, R! R, G- [' q) s6 _5 N  t$ Q* m+ f8 @( w
API调用# d$ k( H3 M! l' H: Z% M
nova.servers.evacuate(server=fm['id']), on_shared_storage=True
3 J# s. b/ t+ g$ c) \! R% y, Q1. on_shared_storage参数在2.14版本后废除,自动检查是否为共享存储。  p( G0 ]& H6 d/ D
    共享存储能够保证实例在另外新节点重建后数据不丢失* k8 p4 \  }3 a+ e( y/ t7 {- q1 H
2. 可以设置目的主机host
2 H! ]: V4 D3 l    如果不设置host,nova会通过scheduler选择一个新的主机(不会分到原主机,因为rebuild函数中过滤了原主机)/ e) `& C6 J  M& P
3. 这个调用只是发送了evacuate操作命令,具体是否真正疏散成功,无法知道# W9 E. Y  z$ S/ I8 M0 e. f* u
9 U0 A5 H4 A( V- Q
源码分析
4 P7 G: H) Q& g: r$ }( m/ b1 U对应的是/nova/compute/api.py
: N7 k! x0 z0 R8 C1 {) o4 c4 A( e@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,3 k. s* W/ y  F: V" A! C% ~
                                vm_states.ERROR])3 D  S0 y2 w" E6 h9 t) U
def evacuate(self, context, instance, host, on_shared_storage,' z0 `  g5 m4 o) U0 _
            admin_password=None)" }/ P# P6 C, x9 d
1. 函数上方有装饰符 @check_instance_state
* @2 t7 W2 F4 K+ ^6 Q表示在执行evacuate方法前先执行check_instance_state:检测传入的instance的vm_state是否为ACTIVE、STOPPED或ERROR。如果不是这三种状态,不能执行evacuate方法。1 W  ]& }0 D+ b5 D- l

7 ^& Q+ ?+ u& Q" L2. 首先检测instance所在主机的状态是否为down,如果不是down(比如up),执行会出错。. c0 e" t0 X$ y: O
LOG.debug('vm evacuation scheduled', instance=instance)
( c* r( o* _* K9 T5 K( p/ V- J# 原实例所在主机, y+ K, W2 X. z8 B+ D
inst_host = instance.host
& n" l* G' [, o! bservice = objects.Service.get_by_compute_host(context, inst_host)
9 F: I5 e( n0 A. f9 }# Z+ x4 n# 首先确保compute主机的状态为down( z6 n, t' Y4 v! S9 |
if self.servicegroup_api.service_is_up(service):
, T+ ]2 @8 f9 B; ]% q# M    LOG.error(_LE('Instance compute service state on %s '' R4 O- r: z. p( B1 L9 F: U
                  'expected to be down, but it was up.'), inst_host)
3 O+ B* K  T' Z/ B% t    raise exception.ComputeServiceInUse(host=inst_host)
! f9 }$ U$ K  E+ k6 d. L9 V  Y: \; G; w) a' G2 w+ D9 ^, w6 m: Q
3. 记录action执行操作
1 O( `3 x2 P1 |% E6 F. u2 ]# 实例的任务状态设置为REBUILDING
5 J/ G3 z( r' U# P$ u* X' Z. E/ ]instance.task_state = task_states.REBUILDING
# h, ?( K& S: i! c; u. Q, K# Linstance.save(expected_task_state=[None])
: Z* v. d: l  i) t- _! bself._record_action_start(context, instance, instance_actions.EVACUATE)
) s- F% Y$ Z/ O7 p) G4 p, L/ s# D3 e+ v0 }
4. 初始化迁移类0 ^1 n4 n9 Y# T  N$ F3 t3 P
migration = objects.Migration(context,9 Y  O# w% M& b5 n' y0 u& m
                              source_compute=instance.host,
5 E# A- g7 [& o! H2 W4 u                              source_node=instance.node,2 x- f. u' [& E  x; t3 E
                              instance_uuid=instance_uuid,
7 \8 w$ H6 r6 t) t& p; S' R                              status='accepted',  C* J/ k+ {8 U( d( U2 z
                              migration_type='evacuation')6 ?- o3 K$ ?2 i7 a
5. 创建迁移(这里为什么要创建migration,并没有执行迁移)
  o/ k9 {1 F* W6 L! s! k( k: a# 如果提供了目的主机1 H7 O  a) V& C* A+ Y/ ^. e1 f. |
if host:
* b3 v6 }9 N+ G8 B* K    migration.dest_compute = host1 M# r' b0 z9 I0 v2 S4 h
migration.create()3 B- G: C' v7 B

4 Y7 T/ R" n- L; x6. 发送消息通知实例的使用配额
' _# D# ^- T" [compute_utils.notify_about_instance_usage(
0 b6 i5 c4 ?' f, G    self.notifier, context, instance, "evacuate")
6 y2 w+ L9 y& ]! k6 v1 V! C9 [& f: J* n9 M) d4 ^$ F7 a' R( `
7. 最后执行task任务:rebuild_instance3 r2 F' R) f- \2 N
所以evacuate的本质是在新节点上执行rebuild操作
# j) L! W  X/ B1 [  jreturn self.compute_task_api.rebuild_instance(context,, U% v: G) D% @1 b6 c
            instance=instance,
' P# f% O& S. `! A* I9 ~            new_pass=admin_password,5 L0 e0 W; z8 W% d8 u# [7 u' Z
            injected_files=None,3 I9 z/ C) L; ?! A) z, B# D; ~
            image_ref=None,* z: L* S7 c8 h% E5 s
            orig_image_ref=None,
6 ?8 M2 v1 b. q( i- E8 Z            orig_sys_metadata=None,/ d; Z8 U& w; U# W( v: A) T
            bdms=None,
# Y+ i3 W* \% o9 u            recreate=True,+ O6 J3 N+ D6 \8 _! x# T
            on_shared_storage=on_shared_storage,
# h5 {( p; ^) M* U( r1 Q4 Y6 l% d, }            host=host)% m) T6 I) ?/ \" z
深入分析rebuild_instance方法,通过各种rpc调用,最终具体执行的是/nova/conductor/manager.py
3 t& J2 ~" d- i7 X+ v( V6 @def rebuild_instance(self, context, instance, orig_image_ref, image_ref,
0 ]' G$ ]. ]; ]$ ^. I5 I! t                    injected_files, new_pass, orig_sys_metadata,* T9 {. z3 r: Y
                    bdms, recreate, on_shared_storage,
, i  @& W. ?: k4 t+ I, g# R                    preserve_ephemeral=False, host=None):. }& A1 u4 d3 Y& s8 f) a
(1)在选择新目的主机时先排除instance所在主机
# B) @( B/ w' m# N& d2 T3 k& N这样能确保不会在原主机上执行rebuild操作6 c8 [4 {" k9 r  G4 N3 k! Z3 O
# 排除原实例所在的主机,即不能在同一个主机里进行rebuild
! j* z$ S. u' ffilter_properties = {'ignore_hosts': [instance.host]}  Y( [$ C0 k! m6 g5 t8 T. m
hosts = self.scheduler_client.select_destinations(context,
) t8 r  J" R: b; H1 [$ o5 h                                        request_spec,/ F9 F5 {7 w7 e
                                        filter_properties)
6 u* o8 v2 e' s: t" f* b; W8 }0 G(2)接下来会通过scheduler模块筛选出合适的新主机
! l$ N- ^  q% t4 o9 x+ P( g(3)如果没有选出足够的合适新主机,则抛出异常  ]) J0 G: W. y( }) r3 }! ^/ J
except exception.NoValidHost as ex:, [0 z' d8 U, b9 f, \% g# H
    with excutils.save_and_reraise_exception():9 c1 [; v2 F( T2 i) E
        self._set_vm_state_and_notify(context, instance.uuid,
' X* ]& Q* `" |* o1 `3 c            'rebuild_server',6 }) l4 D; }- C8 h; v. S4 K" o* s
            {'vm_state': instance.vm_state,
7 s5 S$ T4 a0 Q- y            'task_state': None}, ex, request_spec)1 z# i0 f: O  C) n# w9 M4 h
        LOG.warning(_LW("No valid host found for rebuild"),6 N7 A8 x4 ~& M) e7 o& f$ ~
                    instance=instance)
  F$ T+ M( _3 q  |2 w不能选出合适的新主机,有可能是除了原节点外,其他节点都不可用(computer service status:disabled)或网络不通(computer service state:down),导致没有合适的新主机。" S( [" v2 ]4 v) A9 Q
% Z  R) ]/ L# s0 Q8 P
您需要登录后才可以回帖 登录 | 注册

本版积分规则

返回首页|Archiver|手机版|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )

GMT+8, 2026-6-12 00:00 , Processed in 0.031829 second(s), 23 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表