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

Nova - evacuate疏散

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2021-7-27 12:00:06 | 显示全部楼层 |阅读模式
当实例所在的节点发生故障不可用时,可执行evacuate操作,在另外一个新节点rebuild该实例,实现高可用。
/ M, O, i2 ^& m* j* U2 t$ o6 [9 W- |/ u这可以是OpenStack计算节点HA的一种实现方案。
; O: D# b) {0 P4 l/ B" j) |5 U( K9 O; p* d
API调用, ]% E: j* P. Y! l: W
nova.servers.evacuate(server=fm['id']), on_shared_storage=True
* P5 ~& d/ j# m, [: k* L; F1. on_shared_storage参数在2.14版本后废除,自动检查是否为共享存储。
/ O# a1 t4 w8 p8 a/ B/ d    共享存储能够保证实例在另外新节点重建后数据不丢失3 N8 z# s4 K% b* L; F  I1 E
2. 可以设置目的主机host/ q/ x8 M( y3 |: Y
    如果不设置host,nova会通过scheduler选择一个新的主机(不会分到原主机,因为rebuild函数中过滤了原主机)
  E3 r5 v. [; t0 h& N7 |2 I2 x3. 这个调用只是发送了evacuate操作命令,具体是否真正疏散成功,无法知道6 r: y; |! ~* L/ T
+ K3 ?2 D1 e2 z1 d4 [- f9 H
源码分析
% O4 ?! o9 y' V7 _$ X对应的是/nova/compute/api.py
: N$ z) U  K8 Z# n@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,, H$ }9 c8 h1 v0 B8 d  S
                                vm_states.ERROR])& ~" o4 b5 U1 ~( f' S
def evacuate(self, context, instance, host, on_shared_storage,
/ |0 J; y& a0 W% z5 H2 I            admin_password=None)
4 |2 X! T, u5 ?2 q" {1. 函数上方有装饰符 @check_instance_state& e5 o. y) I! x5 ^3 v5 o; i
表示在执行evacuate方法前先执行check_instance_state:检测传入的instance的vm_state是否为ACTIVE、STOPPED或ERROR。如果不是这三种状态,不能执行evacuate方法。
' K- b1 L5 b9 F2 ]7 `% J+ O( u: J/ ?( e! q# o! d$ i
2. 首先检测instance所在主机的状态是否为down,如果不是down(比如up),执行会出错。
+ `& j1 i2 b  LLOG.debug('vm evacuation scheduled', instance=instance), b' a6 |/ B5 S) Z. ^" f# N
# 原实例所在主机
7 W0 @2 _& `- |" K8 _. Yinst_host = instance.host
9 U& h" V. D3 P( T1 eservice = objects.Service.get_by_compute_host(context, inst_host)  y6 Z# w! ^; v# Q" M
# 首先确保compute主机的状态为down
+ g. u& X/ D6 K3 v5 j# @if self.servicegroup_api.service_is_up(service):
9 S2 f6 L% g. o) T2 j    LOG.error(_LE('Instance compute service state on %s '
) ?. d+ B( H4 C8 N- u                  'expected to be down, but it was up.'), inst_host)" ?! C  X5 G: G3 u
    raise exception.ComputeServiceInUse(host=inst_host)$ T: H4 k$ e  ?

" L! H$ Y, X, [3. 记录action执行操作
0 _% H; t! n. J+ O# 实例的任务状态设置为REBUILDING
6 X* @$ v6 R7 Ninstance.task_state = task_states.REBUILDING0 F  N1 Y, u) X: b2 J
instance.save(expected_task_state=[None])
# @/ L& F' d# L* \self._record_action_start(context, instance, instance_actions.EVACUATE)( v6 E! Z( y; P4 F8 t4 i! g4 J
/ K( m+ }5 i1 Q$ D; V" O0 W" r4 q+ b
4. 初始化迁移类
) |2 _- F2 K4 s5 C8 u8 _" Q* x( Tmigration = objects.Migration(context,* a8 j/ u3 N6 V: u2 Q& D0 g. B
                              source_compute=instance.host,
: Q1 \4 M( `" J                              source_node=instance.node,
2 ]& O8 L- u8 r& T" `                              instance_uuid=instance_uuid,9 F+ U: I% s- ?
                              status='accepted',
8 }' n( I) Y6 k7 K4 A3 F/ X8 W                              migration_type='evacuation')
; s! d. H3 ?) W0 F2 t& H$ `5. 创建迁移(这里为什么要创建migration,并没有执行迁移)
9 ]$ y) h9 [  L% L+ J# 如果提供了目的主机6 n( G8 P8 V/ ~+ O! x
if host:
3 Z1 [" r; Z' w$ C& m1 S" g    migration.dest_compute = host
8 n2 I! k4 `1 V5 {- }2 Hmigration.create(). p4 e( J' i+ y8 l

' Q( l$ h+ q% \7 t1 o/ |9 g6. 发送消息通知实例的使用配额
6 ?4 q3 Z; s% t/ k9 u, z) Bcompute_utils.notify_about_instance_usage($ p* l1 x  J7 w# o3 _- v+ a
    self.notifier, context, instance, "evacuate")6 w- h* Q/ `5 _! p) @: j
: _6 `" r! E; |" a4 l
7. 最后执行task任务:rebuild_instance  m8 F5 u8 |. e# k
所以evacuate的本质是在新节点上执行rebuild操作
/ V9 @3 K- o0 h2 i( j' Areturn self.compute_task_api.rebuild_instance(context,( V; g0 C/ W; Z7 k4 l1 q& h
            instance=instance,4 t/ N7 Y5 C- s# u
            new_pass=admin_password,
  S- P( f7 x8 e- L7 u6 I) w            injected_files=None,/ N" Q  u( E3 c  n' u, y- N
            image_ref=None,
. P+ A' f/ O4 I3 @8 s% f. n            orig_image_ref=None,( {+ \2 M; a5 `1 _- G
            orig_sys_metadata=None,
2 n1 Q$ a0 l/ |! V/ p- M            bdms=None,
' C5 S) Y% l5 ~& w6 r            recreate=True,
! e3 F5 @! h& g$ }" ^            on_shared_storage=on_shared_storage,
7 z: L" d$ R/ i            host=host)
6 T2 K( h4 E6 `" h深入分析rebuild_instance方法,通过各种rpc调用,最终具体执行的是/nova/conductor/manager.py
# b! G$ i& V. B" \4 y- M- Vdef rebuild_instance(self, context, instance, orig_image_ref, image_ref,
/ j: ]' u& J& Q* Q6 i5 N! U' [                    injected_files, new_pass, orig_sys_metadata,
2 |+ ?; }1 u, W8 ?( T5 [                    bdms, recreate, on_shared_storage,. q) q5 m$ k! L' a7 [
                    preserve_ephemeral=False, host=None):, f: R! h+ Y1 ~6 ]
(1)在选择新目的主机时先排除instance所在主机
# i6 R! M. |. J' A, Q# W8 W7 Y这样能确保不会在原主机上执行rebuild操作
0 R$ {! t7 X5 D+ v# 排除原实例所在的主机,即不能在同一个主机里进行rebuild: ^0 }* I" t+ x' k
filter_properties = {'ignore_hosts': [instance.host]}. }& P7 r) j' Q$ K) g- H% T: a
hosts = self.scheduler_client.select_destinations(context,; N, W) N7 _4 E' {3 O* `/ i
                                        request_spec,
8 j; B- a) C, T& y7 V7 L6 f                                        filter_properties)
, d6 C3 f; D7 I, [& f(2)接下来会通过scheduler模块筛选出合适的新主机/ `* V) Z. \7 k/ S% y6 A
(3)如果没有选出足够的合适新主机,则抛出异常
5 s' L7 n4 o. q$ _- `. x! Oexcept exception.NoValidHost as ex:' N! i" f; B! Q8 a
    with excutils.save_and_reraise_exception():- k. _, B# a, L5 p$ c  I
        self._set_vm_state_and_notify(context, instance.uuid,; \: ]" I: D& F" s! w8 Z* T$ K
            'rebuild_server',
5 X& }( ~% {1 ~) E$ B            {'vm_state': instance.vm_state,
/ O9 F4 F( }2 M  w' d  j0 x( s            'task_state': None}, ex, request_spec)3 Y3 g9 M5 h' J) x/ o) Q$ R; t
        LOG.warning(_LW("No valid host found for rebuild"),
: `# p, L# s% r# r0 }! ~- X$ p                    instance=instance)
& S  r* c$ i+ h' T不能选出合适的新主机,有可能是除了原节点外,其他节点都不可用(computer service status:disabled)或网络不通(computer service state:down),导致没有合适的新主机。
4 ~; i" q( M6 J# E5 Q) t" Y% ~6 j, S: |, @
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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