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

Nova - evacuate疏散

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2021-7-27 12:00:06 | 显示全部楼层 |阅读模式
当实例所在的节点发生故障不可用时,可执行evacuate操作,在另外一个新节点rebuild该实例,实现高可用。
% a3 m6 w0 ?% O! I- i这可以是OpenStack计算节点HA的一种实现方案。
" K9 d7 I+ S! b+ P% f% i1 C; i$ x0 }# U* |9 G, ~
API调用
/ S6 p& R- B3 ~3 S$ d( d; Lnova.servers.evacuate(server=fm['id']), on_shared_storage=True
1 C4 @7 Z( ~8 V! a8 B4 E* M! ]1. on_shared_storage参数在2.14版本后废除,自动检查是否为共享存储。% C' G: a) a3 N. O0 \
    共享存储能够保证实例在另外新节点重建后数据不丢失, A2 y5 }% {3 }$ C+ f( n* t+ O
2. 可以设置目的主机host/ P! T/ P7 f6 N& g
    如果不设置host,nova会通过scheduler选择一个新的主机(不会分到原主机,因为rebuild函数中过滤了原主机)7 k; P) q& y+ p  g& v! |
3. 这个调用只是发送了evacuate操作命令,具体是否真正疏散成功,无法知道% V" d# f9 E! m9 m5 ^. x$ F

% E$ n- N, t0 D9 b/ C 源码分析5 e: l; }0 N: g$ [* {) b  D
对应的是/nova/compute/api.py# o2 [2 V8 I1 v  j( z% V" Y
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,: ]' _1 Z# [6 m' d- N
                                vm_states.ERROR])
/ b5 ^- F; V0 C- ^, w, _# ldef evacuate(self, context, instance, host, on_shared_storage,! {( P) [+ u5 S  t; ?
            admin_password=None)
, F5 R8 [: w* {7 i. p6 q1. 函数上方有装饰符 @check_instance_state
  s/ B- b6 b0 Y- k- b4 k表示在执行evacuate方法前先执行check_instance_state:检测传入的instance的vm_state是否为ACTIVE、STOPPED或ERROR。如果不是这三种状态,不能执行evacuate方法。
' k) i$ o- S7 S
# C+ o+ g, ^. y  Q  B2. 首先检测instance所在主机的状态是否为down,如果不是down(比如up),执行会出错。
; e* E: o7 h) o* qLOG.debug('vm evacuation scheduled', instance=instance)
5 O/ I3 _' f+ m4 W# 原实例所在主机4 o9 D$ M) ?- {' Q" j1 J
inst_host = instance.host
( r& g3 d4 Z, g- Y1 u8 l/ Yservice = objects.Service.get_by_compute_host(context, inst_host)/ [8 H* g$ G2 F% H# H/ n
# 首先确保compute主机的状态为down' }$ d% @  s5 n2 `4 E0 r
if self.servicegroup_api.service_is_up(service):
$ L0 O' @6 x4 T" p    LOG.error(_LE('Instance compute service state on %s '
2 ~" e8 Q- X: W. P( N) b                  'expected to be down, but it was up.'), inst_host)
, n5 ~5 V9 p0 {; w+ O# Y. w    raise exception.ComputeServiceInUse(host=inst_host)
) U+ X6 K1 e$ ~- R  h( @
% H: H: M; d+ L9 b/ ^3. 记录action执行操作1 ~7 I, i+ @, O$ D6 k1 Y& o
# 实例的任务状态设置为REBUILDING- l4 |1 K6 x3 Y0 I' b6 @
instance.task_state = task_states.REBUILDING
* F# y/ A  \- a3 Yinstance.save(expected_task_state=[None])# h3 R7 Y+ y% j+ V" b
self._record_action_start(context, instance, instance_actions.EVACUATE)
* J: ^1 `+ P' |! i- o5 i- l. v7 [$ N# \. j: Z7 w
4. 初始化迁移类& B* t- C+ j9 H# ~1 I8 R
migration = objects.Migration(context,$ ?# u$ u, `7 l  B( J5 D- u7 l6 e
                              source_compute=instance.host,
4 A  M. K+ l7 \8 f                              source_node=instance.node,7 ~3 W+ z# y# g
                              instance_uuid=instance_uuid,
+ Z9 Z. r' b' G8 V& N" x                              status='accepted',7 T3 g+ t! w- J
                              migration_type='evacuation')" [$ y* J7 g- _. L! j) L8 M
5. 创建迁移(这里为什么要创建migration,并没有执行迁移)
: p& G4 b  h2 P8 G# m# 如果提供了目的主机
; L/ h* z3 d6 f, p8 I. ~" M: J; ~if host:3 W7 g- U7 E" [9 R* t
    migration.dest_compute = host
& z% N: t# W  k- r# x9 fmigration.create()( j( u% `: |$ m/ T

2 ?$ j" A3 [* B6. 发送消息通知实例的使用配额) g2 u1 @* v9 A  c& Q) d
compute_utils.notify_about_instance_usage(: W. l- A0 y2 }0 i
    self.notifier, context, instance, "evacuate")
/ j% d! \8 e$ G  W: q! \' p6 o: }& m9 N& ^5 q9 b
7. 最后执行task任务:rebuild_instance0 e3 Q! M! ^1 J! }. X$ g
所以evacuate的本质是在新节点上执行rebuild操作( P* H: `. W+ P1 K" d# M6 z
return self.compute_task_api.rebuild_instance(context,
& B! T1 v1 s7 f2 J            instance=instance,& l# o, N+ d$ d8 j' b- d& s# t0 E
            new_pass=admin_password,+ S2 F. k' z6 Z  j" S% u
            injected_files=None,
# T+ e* h# O' e0 [3 X. ^! _1 J# t6 o" r            image_ref=None,5 f  D& j/ W) y* A4 }7 {# c1 `/ d0 x
            orig_image_ref=None,
% i% L, H  \1 b5 Q            orig_sys_metadata=None,# l  r; v$ k2 b
            bdms=None,7 |  `& o* B4 k) k, s3 z
            recreate=True,' f/ ]4 y6 a/ A8 G
            on_shared_storage=on_shared_storage,
- d% B. k+ s: ?2 l- m: Q            host=host)
' G# t( l) S" h深入分析rebuild_instance方法,通过各种rpc调用,最终具体执行的是/nova/conductor/manager.py6 d/ v: ]3 N: s% n9 z
def rebuild_instance(self, context, instance, orig_image_ref, image_ref,
4 I7 k6 B$ O. o9 s7 z( z3 m# L" G                    injected_files, new_pass, orig_sys_metadata,& \& t& \# C0 }: @, c% h% b
                    bdms, recreate, on_shared_storage,
3 @$ L) q5 ]1 a8 p8 v2 j9 V                    preserve_ephemeral=False, host=None):
! M/ {" }/ T+ {& F. t! J(1)在选择新目的主机时先排除instance所在主机6 A" U4 P- k0 I: I7 @" v
这样能确保不会在原主机上执行rebuild操作2 Q) m/ j( f8 u( w* e
# 排除原实例所在的主机,即不能在同一个主机里进行rebuild; e9 f" r' |9 I- q( |. f+ z3 @
filter_properties = {'ignore_hosts': [instance.host]}/ s" I2 r" x* w! n' A
hosts = self.scheduler_client.select_destinations(context,
- p/ I, k- j! T6 g3 g                                        request_spec,$ |. b& U; y+ ]- C" w6 K9 \6 q
                                        filter_properties)4 M9 r; R* G5 ]* B1 B# o4 z+ S
(2)接下来会通过scheduler模块筛选出合适的新主机
2 R/ b9 l) ^2 I(3)如果没有选出足够的合适新主机,则抛出异常7 i1 g/ N. I2 l: u
except exception.NoValidHost as ex:' o8 P3 ~& Y9 b
    with excutils.save_and_reraise_exception():
' g: r+ p4 N0 k8 g        self._set_vm_state_and_notify(context, instance.uuid,9 A/ C! K" E7 \4 s9 J
            'rebuild_server',. M  N  h" _, h. i1 z! i7 d  p
            {'vm_state': instance.vm_state,
# w. l& y  l7 ?; R7 S  ?' Q; }            'task_state': None}, ex, request_spec)2 u7 m0 }) @+ C( L! ?; F9 q
        LOG.warning(_LW("No valid host found for rebuild"),: D5 [9 v- Z/ I/ S# O
                    instance=instance)7 P0 m9 b, l! q/ e0 d: K
不能选出合适的新主机,有可能是除了原节点外,其他节点都不可用(computer service status:disabled)或网络不通(computer service state:down),导致没有合适的新主机。
( H+ O! @) n9 @+ I; ^
$ z" a+ I% z" R% W9 V4 ^6 O
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-6-12 00:03 , Processed in 0.013979 second(s), 22 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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