Loading

qemo COLO特性

参考文档
https://github.com/qemu/qemu/blob/master/docs/COLO-FT.txt
https://github.com/qemu/qemu/blob/master/docs/block-replication.txt

目标

实现虚拟机服务不停止的高可用。两个虚拟机互为主备。

原理

如何保证虚拟机的一致?

  1. 控制网络请求,主虚拟机的每一份网络请求都会复制给备份虚拟机。

    Note: 也就是说明,虚拟机的所有网卡都必须给colo接管。否则它就控制不了。

  2. 保持磁盘数据的实时同步。

NOTE:

本质上就是通过修改网络数据包跟磁盘IO方向来实现同步。

特性说明

BlockReplication

为了支持磁盘实时同步而引入的特性。这是colo运行的基础。所以得先弄懂。

工作流:

image

说明:

1: copy and dorward

主虚拟机的任何写操作都会复制一份到备份虚拟机。尝试写入备份虚拟机的磁盘。如果有人写入了,那么它就不再写入。这个最后有解释为什么。

2:

备份虚拟机自己操作的磁盘其实是active disk , 尽管Secondary Disk是备份虚拟机的数据磁盘,但是备份虚拟机在colo正常的模式

下,备份虚拟机使用的是active disk。而不是自己的数据盘。这个结合下图看比较好。原理是这样的。其实activate disk 跟 hidden disk都是secondary的增量盘,也就是使用cow技术,对于secondary disk的修改,写到 activate disk 中。读取则照常读取secondary盘。

3:以上的图与下面的架构图名称有点冲突,应该写Activate DISK会好一点。

架构图

image

说明:

前置说明:

  1. 主虚拟机有一个磁盘,而备份虚拟机需要三个磁盘,一个数据盘,一个缓存盘,一个活动磁盘
  2. qemu 支持磁盘合成,也就是顶层正常访问IO,但是这些IO可以分配给实际不同的磁盘来源。跟条带化有点像。

1:

虚拟机通过virtio-blk驱动访问磁盘,但是磁盘由两部分组成,一个是Primary,一个是NBD Client。策略采用read-pattern=fifo,这个虚拟机配置文件会有体现,也就是读取只从Primary disk读取,写入则,两个子磁盘都需要写入。

2:备份虚拟机会运行一个NBD SERVER服务,用于接收来自主虚拟机NBD CLIENT的写入请求。写入请求先尝试直接写入备份虚拟机的数据盘,如果失败,则先写入缓冲盘,也就是hidden-disk,文中称为隐藏盘。hidden-disk会以异步的形式将数据写入数据盘,当然,这个任务由colo启动。

3:最后一个是activate磁盘。需要注意的是,activate上面写着2 filter这个与主虚拟机nbd client上边连接的2 filter名称一样,这个是有意义的。

activate是一个虚盘,备份虚拟机启动的时候,这是一个空盘,包括hidden缓存盘也是一样,一开始都是空盘。activate会接收来自主虚拟机的磁盘数据。同时,当你在备份虚拟机进行操作时,写入的数据也是落到这个盘的,并不会影响备份虚拟机的数据盘,所以即使写了也会被很快覆盖掉。

具体配置如下:

#备份虚拟机的配置
# 注意mode的模式为 secondary, 同时驱动类型为replication,也就是它的数据来自于另一模式为mode=primary
# 至于 top-id
# 指向的是自己的另一个驱动
-drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
children.0=childs0 \
   -incoming tcp:0.0.0.0:9998
   
# -incoming 说明这个驱动来自于网络的推送。
# 也就是来自主虚拟机的推送。所以在主虚拟机需要执行
# {'execute': 'migrate', 'arguments': {'uri': 'tcp:127.0.0.2:9998' } }


-drive if=none,id=childs0,driver=replication,mode=secondary,file.driver=qcow2,\


top-id=colo-disk0,file.file.filename=$imagefolder/secondary-active.qcow2,\


file.backing.driver=qcow2,file.backing.file.filename=$imagefolder/secondary-hidden.qcow2,\


file.backing.backing=parent0 \

# 所以,你需要在主虚拟机执行这个
{'execute': 'human-monitor-command', 'arguments': {'command-line': 'drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0'}}


总结:

  1. 同个节点ID 一样说明执行同个东西,但是跨节点的话,两个名称一样的ID 就没有任何关系。

    节点之间的连接只有socket

  2. {'execute': 'migrate', 'arguments': {'uri': 'tcp:127.0.0.2:9998' } } 这个来自主节点的数据推送是一直在后台执行的。

  3. 在启动虚拟机,组成主备之前,主虚拟机以及备份虚拟机的数据盘数据要一致!!!,因为后面只会同步更改的数据。磁盘的完全同步要手动去触发。

  4. checkpoint 会定时打同步点。在此点,两个虚拟机状态完全一致,至于如何运作。虚拟机一开始启动是否会默认主备数据盘已经一致,并打一个checkpoint ,后面如何生效,这还不知道!

COLO-PROXY

用于比较网络数据包。如果主备虚拟机对网络请求的响应数据不一致则触发checkpoint

image

说明:

网络数据包的镜像拷贝,转发,通过netfilter来实现。也就是iptable工作的那个内核层。

工作流程:

  1. TAP代表网卡,首先网卡接受到一个数据包
  2. 数据包经过filter mirror规则生成两份数据包,一份发送给备份虚拟机,一份发送给主虚拟机执行请求处理。
  3. 备份虚拟接收到数据包之后,修改TCP包中的ACK以及SEQ号码,这个是TCP的规范。否则TCP连接会出错。
  4. 调整完之后,备份虚拟机将数据包发送给主机进行请求处理
  5. 之后,主虚拟机,以及备份虚拟机处理完成的数据包都发送给colo compare模块,进行数据包对比操作。如果出错则触发checkpoint,如果成功,则将数据包发送回去。

Note:

对于每个数据包,主虚拟机都会先进入队列,因为不能保证备份虚拟机的响应能够正常,所以主虚拟机需要先把网络数据包缓存起来,如果触发checkpoint,则需要重发在队列中的数据包。

配置流程说明

来源https://github.com/qemu/qemu/blob/master/docs/COLO-FT.txt

步骤一:启动主虚拟机

1. Primary:
Note: Initially, $imagefolder/primary.qcow2 needs to be copied to all hosts.
You don't need to change any IP's here, because 0.0.0.0 listens on any
interface. The chardev's with 127.0.0.1 IP's loopback to the local qemu
instance.

# imagefolder="/mnt/vms/colo-test-primary"

# qemu-system-x86_64 -enable-kvm -cpu qemu64,kvmclock=on -m 512 -smp 1 -qmp stdio \
   -device piix3-usb-uhci -device usb-tablet -name primary \
   -netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \
   -device rtl8139,id=e0,netdev=hn0 \
   -chardev socket,id=mirror0,host=0.0.0.0,port=9003,server=on,wait=off \
   -chardev socket,id=compare1,host=0.0.0.0,port=9004,server=on,wait=on \
   -chardev socket,id=compare0,host=127.0.0.1,port=9001,server=on,wait=off \
   -chardev socket,id=compare0-0,host=127.0.0.1,port=9001 \
   -chardev socket,id=compare_out,host=127.0.0.1,port=9005,server=on,wait=off \
   -chardev socket,id=compare_out0,host=127.0.0.1,port=9005 \
   -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 \
   -object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out \
   -object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 \
   -object iothread,id=iothread1 \
   -object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,\
outdev=compare_out0,iothread=iothread1 \
   -drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
children.0.file.filename=$imagefolder/primary.qcow2,children.0.driver=qcow2 -S

说明:前面几个参数没用,重点关注chardevobject,chardev为给虚拟机创建一个字符设备,object为参数配置。

网络请求部分:

  1. 端口9003 socket设备用于发送网络数据包给备份虚拟机

  2. 端口9004socket设备用于接收来自备份虚拟机的响应数据包

  3. filter-mirror用于配置数据包镜像复制,跟ffmpeg-filter滤镜语法有点像,将netdev=hn0的数据包全部复制一份到mirror0

  4. filter-redirector用于重定向,将indev=compare_out输入重定向netdev=hn0,这个标识的是最终返回给网络请求的数据包。

  5. filter-redirector用于重定向,将netdev=hn0重定向到outdev=compare0

  6. -object colo-compare用于配置colo框架。

    primary_in: 主虚拟机的网络输入

    secondary_in: 备份虚拟机的网络输入

    outdev=compare_out0: 将结果输出到compare_out0中

    所以整个网络请求的路径为

    主虚拟机接收到的网络请求--> 复制一份到mirro0,同时重定向到compare0,【这个跟compare0-0是一样的目的地】

    -> 接收来自备份虚拟机的响应compare1, -> 接收来自主虚拟机的响应compare0-0,比较操作之后将数据包丢给compare_out0

    -->compare_out0通过转发规则转给网卡netdev=hn0

  7. 在网络请求过程中,会有一个比较数据包的操作,也就是主备虚拟机的响应数据包应该严格一致。如果不一致,则会触发同步。怎么同步? 猜测应该是从上一个checkpoint开始同步。

磁盘部分:

-drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
children.0.file.filename=$imagefolder/primary.qcow2,children.0.driver=qcow2 -S

磁盘驱动为driver=quorum,意味着有一个投票选择的过程,策略为read-pattern=fifo也就是读取数据时。从子节点第一个

children.0.file.filename,读取数据,写入数据则写入所有子节点。所以后面还有个配置子节点的qmp命令,即配置NDB

为第四步的这个操作:配置 replication0

{'execute':'qmp_capabilities'}
{'execute': 'human-monitor-command', 'arguments': {'command-line': 'drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0'}}
{'execute': 'x-blockdev-change', 'arguments':{'parent': 'colo-disk0', 'node': 'replication0' } }
{'execute': 'migrate-set-capabilities', 'arguments': {'capabilities': [ {'capability': 'x-colo', 'state': true } ] } }
{'execute': 'migrate', 'arguments': {'uri': 'tcp:127.0.0.2:9998' } }

步骤二:启动备份虚拟机

# qemu-system-x86_64 -enable-kvm -cpu qemu64,kvmclock=on -m 512 -smp 1 -qmp stdio \
   -device piix3-usb-uhci -device usb-tablet -name secondary \
   -netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \
   -device rtl8139,id=e0,netdev=hn0 \
   -chardev socket,id=red0,host=$primary_ip,port=9003,reconnect=1 \
   -chardev socket,id=red1,host=$primary_ip,port=9004,reconnect=1 \
   -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 \
   -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 \
   -object filter-rewriter,id=rew0,netdev=hn0,queue=all \
   -drive if=none,id=parent0,file.filename=$imagefolder/primary.qcow2,driver=qcow2 \
   -drive if=none,id=childs0,driver=replication,mode=secondary,file.driver=qcow2,\
top-id=colo-disk0,file.file.filename=$imagefolder/secondary-active.qcow2,\
file.backing.driver=qcow2,file.backing.file.filename=$imagefolder/secondary-hidden.qcow2,\
file.backing.backing=parent0 \
   -drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\
children.0=childs0 \
   -incoming tcp:0.0.0.0:9998

说明:

  1. 端口9003 连接主虚拟机接收数据包

  2. 端口9004 连接主虚拟机发送响应数据包

  3. -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0

    修改网卡的输入来自于red0

  4. -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 \

    网卡接收的数据包重定向red1

  5. -drive if=ide,id=colo-disk0,driver=quorum,read-pattern=fifo,vote-threshold=1,\ children.0=childs0 \ -incoming tcp:0.0.0.0:9998

    配置一个磁盘驱动,数据来自主虚拟机通过NBD推送的数据。同时它有一个子盘childs0 ,也就是数据的写入同时会写入

    childs0,读取则从-incoming tcp:0.0.0.0:9998读取数据。

  6. -drive if=none,id=parent0,file.filename=$imagefolder/primary.qcow2,driver=qcow2

    定义备份虚拟机数据盘。

    注意:

    为什么这里primary.qcow2,跟主虚拟机的数据盘一样?因为它就是拷贝主虚拟机的数据盘!它默认你主备虚拟机数据盘已经完全一样了!

  7. 下面一条是最为核心的语句

    -drive if=none,id=childs0,driver=replication,mode=secondary,file.driver=qcow2,\
    top-id=colo-disk0,file.file.filename=$imagefolder/secondary-active.qcow2,\
    file.backing.driver=qcow2,file.backing.file.filename=$imagefolder/secondary-hidden.qcow2,\
    file.backing.backing=parent0
    
    # id 为 childs0 说明它会被第5条引用,它接收来自-incoming tcp:0.0.0.0:9998`的数据。
    #同时驱动类型为replication, mode为mode=secondary 所以它会被动的写入数据。这个盘指向的是active盘
    # 所以这是备份虚拟机看到的真正的系统盘
    
    # 同时它配置了file.backing.driver 缓存盘
    # 以及缓存盘指向的目标 file.backing.backing=parent0 这才是数据盘。
    # 这两个参数为`colo`框架使用,也就是最开始讲的块复制流程所需要的参数。
    

步骤三:备份虚拟机启动NBD服务端,用于接收主虚拟机推送的数据


{'execute':'qmp_capabilities'}
{'execute': 'nbd-server-start', 'arguments': {'addr': {'type': 'inet', 'data': {'host': '0.0.0.0', 'port': '9999'} } } }
{'execute': 'nbd-server-add', 'arguments': {'device': 'parent0', 'writable': true } }

# 直接写向备份虚拟机数据盘

步骤四:主虚拟机将数据盘数据推送向NBD服务端

{'execute':'qmp_capabilities'}
{'execute': 'human-monitor-command', 'arguments': {'command-line': 'drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0'}}
{'execute': 'x-blockdev-change', 'arguments':{'parent': 'colo-disk0', 'node': 'replication0' } }
{'execute': 'migrate-set-capabilities', 'arguments': {'capabilities': [ {'capability': 'x-colo', 'state': true } ] } }
{'execute': 'migrate', 'arguments': {'uri': 'tcp:127.0.0.2:9998' } }

到这里:主备双系统正常运行了!

故障恢复:

情形一:

备份虚拟机挂了,主虚拟机需要先把备份虚拟机的参数移除掉。

{'execute': 'x-blockdev-change', 'arguments':{ 'parent': 'colo-disk0', 'child': 'children.1'} }
# 移除 colo-disk0 的子盘也就是备份虚拟机的磁盘

{'execute': 'human-monitor-command', 'arguments':{ 'command-line': 'drive_del replication0' } }
# 删除复制设备

{'execute': 'object-del', 'arguments':{ 'id': 'comp0' } }
# 删除对象参数, 就是逆操作。把原来修改网络路径改改了。不要再发送给备份虚拟机了

{'execute': 'object-del', 'arguments':{ 'id': 'iothread1' } }
{'execute': 'object-del', 'arguments':{ 'id': 'm0' } }
{'execute': 'object-del', 'arguments':{ 'id': 'redire0' } }
{'execute': 'object-del', 'arguments':{ 'id': 'redire1' } }
{'execute': 'x-colo-lost-heartbeat' }

恢复新添加的备份虚拟机

# 在新的备份虚拟机执行第二步以及第三步
# 之后在主虚拟机主动同步备份虚拟机磁盘

{'execute': 'drive-mirror', 'arguments':{ 'device': 'colo-disk0', 'job-id': 'resync', 'target': 'nbd://127.0.0.2:9999/parent0', 'mode': 'existing', 'format': 'raw', 'sync': 'full'} }

# 同步完成之后
# 取消同步任务
Wait until disk is synced, then:
{'execute': 'stop'}
{'execute': 'block-job-cancel', 'arguments':{ 'device': 'resync'} }

# 添加NBD设备,实时同步主虚拟机磁盘与备份虚拟机磁盘
{'execute': 'human-monitor-command', 'arguments':{ 'command-line': 'drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.2,file.port=9999,file.export=parent0,node-name=replication0'}}
{'execute': 'x-blockdev-change', 'arguments':{ 'parent': 'colo-disk0', 'node': 'replication0' } }

# 配置网卡部分参数,执行网卡数据包重定向以及数据包的对比配置

{'execute': 'object-add', 'arguments':{ 'qom-type': 'filter-mirror', 'id': 'm0', 'props': { 'netdev': 'hn0', 'queue': 'tx', 'outdev': 'mirror0' } } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'filter-redirector', 'id': 'redire0', 'props': { 'netdev': 'hn0', 'queue': 'rx', 'indev': 'compare_out' } } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'filter-redirector', 'id': 'redire1', 'props': { 'netdev': 'hn0', 'queue': 'rx', 'outdev': 'compare0' } } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'iothread', 'id': 'iothread1' } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'colo-compare', 'id': 'comp0', 'props': { 'primary_in': 'compare0-0', 'secondary_in': 'compare1', 'outdev': 'compare_out0', 'iothread': 'iothread1' } } }

# 启动推送磁盘数据任务
{'execute': 'migrate-set-capabilities', 'arguments':{ 'capabilities': [ {'capability': 'x-colo', 'state': true } ] } }
{'execute': 'migrate', 'arguments':{ 'uri': 'tcp:127.0.0.2:9998' } }


情景二:

主虚拟机挂了,备份虚拟机需要升级为主虚拟机

{'execute': 'nbd-server-stop'}
# 停止nbd服务,因为不需要再接收数据了

{'execute': 'x-colo-lost-heartbeat'}
# 把备份虚拟机缓存盘的数据刷回去先,现在备份虚拟机升级为主虚拟机了。

{'execute': 'object-del', 'arguments':{ 'id': 'f2' } }
{'execute': 'object-del', 'arguments':{ 'id': 'f1' } }

# 删除网卡重定向的设备
{'execute': 'chardev-remove', 'arguments':{ 'id': 'red1' } }
{'execute': 'chardev-remove', 'arguments':{ 'id': 'red0' } }

# 跟第一步操作一样,改成用qmp命令来动态修改。而不是在启动命令中配置。
# 准备作为主虚拟机需要的资源
{'execute': 'chardev-add', 'arguments':{ 'id': 'mirror0', 'backend': {'type': 'socket', 'data': {'addr': { 'type': 'inet', 'data': { 'host': '0.0.0.0', 'port': '9003' } }, 'server': true } } } }
{'execute': 'chardev-add', 'arguments':{ 'id': 'compare1', 'backend': {'type': 'socket', 'data': {'addr': { 'type': 'inet', 'data': { 'host': '0.0.0.0', 'port': '9004' } }, 'server': true } } } }
{'execute': 'chardev-add', 'arguments':{ 'id': 'compare0', 'backend': {'type': 'socket', 'data': {'addr': { 'type': 'inet', 'data': { 'host': '127.0.0.1', 'port': '9001' } }, 'server': true } } } }
{'execute': 'chardev-add', 'arguments':{ 'id': 'compare0-0', 'backend': {'type': 'socket', 'data': {'addr': { 'type': 'inet', 'data': { 'host': '127.0.0.1', 'port': '9001' } }, 'server': false } } } }
{'execute': 'chardev-add', 'arguments':{ 'id': 'compare_out', 'backend': {'type': 'socket', 'data': {'addr': { 'type': 'inet', 'data': { 'host': '127.0.0.1', 'port': '9005' } }, 'server': true } } } }
{'execute': 'chardev-add', 'arguments':{ 'id': 'compare_out0', 'backend': {'type': 'socket', 'data': {'addr': { 'type': 'inet', 'data': { 'host': '127.0.0.1', 'port': '9005' } }, 'server': false } } } }


# -------------------------------恢复阶段------------------------------------
# 启动一个新的虚拟机作为备份虚拟机,
# 并执行第三步。备份虚拟机启动NBD服务端。
# 现在原来的备份虚拟机已经成为主虚拟机

# 同步主虚拟机与备份虚拟机
{'execute': 'drive-mirror', 'arguments':{ 'device': 'colo-disk0', 'job-id': 'resync', 'target': 'nbd://127.0.0.1:9999/parent0', 'mode': 'existing', 'format': 'raw', 'sync': 'full'} }


# 停止同步任务
Wait until disk is synced, then:
{'execute': 'stop'}
{'execute': 'block-job-cancel', 'arguments':{ 'device': 'resync' } }

# 主虚拟机添加NBD设备,推送实时的磁盘数据到备份虚拟机
{'execute': 'human-monitor-command', 'arguments':{ 'command-line': 'drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=127.0.0.1,file.port=9999,file.export=parent0,node-name=replication0'}}
{'execute': 'x-blockdev-change', 'arguments':{ 'parent': 'colo-disk0', 'node': 'replication0' } }

# 配置网卡,修改网卡网络发送路径。
{'execute': 'object-add', 'arguments':{ 'qom-type': 'filter-mirror', 'id': 'm0', 'props': { 'insert': 'before', 'position': 'id=rew0', 'netdev': 'hn0', 'queue': 'tx', 'outdev': 'mirror0' } } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'filter-redirector', 'id': 'redire0', 'props': { 'insert': 'before', 'position': 'id=rew0', 'netdev': 'hn0', 'queue': 'rx', 'indev': 'compare_out' } } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'filter-redirector', 'id': 'redire1', 'props': { 'insert': 'before', 'position': 'id=rew0', 'netdev': 'hn0', 'queue': 'rx', 'outdev': 'compare0' } } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'iothread', 'id': 'iothread1' } }
{'execute': 'object-add', 'arguments':{ 'qom-type': 'colo-compare', 'id': 'comp0', 'props': { 'primary_in': 'compare0-0', 'secondary_in': 'compare1', 'outdev': 'compare_out0', 'iothread': 'iothread1' } } }


# 启动数据推送

{'execute': 'migrate-set-capabilities', 'arguments':{ 'capabilities': [ {'capability': 'x-colo', 'state': true } ] } }
{'execute': 'migrate', 'arguments':{ 'uri': 'tcp:127.0.0.1:9998' } }

说明:

  1. 启动x-colo能力的作用?
文档说明
# @x-colo: If enabled, migration will never end, and the state of the VM on the
#          primary side will be migrated continuously to the VM on secondary
#          side, this process is called COarse-Grain LOck Stepping (COLO) for
#          Non-stop Service. (since 2.8)

启动之后migrate将不会停止,一直持续下去。

  1. 发送x-colo-lost-heartbeat的作用

    原文

    # @x-colo-lost-heartbeat:
    #
    # Tell qemu that heartbeat is lost, request it to do takeover procedures.
    # If this command is sent to the PVM, the Primary side will exit COLO mode.
    # If sent to the Secondary, the Secondary side will run failover work,
    # then takes over server operation to become the service VM.
    
    发送给主虚拟机:
    退出COLO模式,别重定向网络流量了,数据也不必推送了。这种情况下
    原本主虚拟机该怎么运行就运行。
    
    发送给备份虚拟机:
    原本备份虚拟机是被动的接收来自主虚拟机的控制,现在备份虚拟机解放了,成为了主虚拟机。
    
  2. x-blockdev-change指定作用

    这个是qenu本身的命令,不是colo引入的,目前只支持Quorum启动。

    原文

    Dynamically reconfigure the block driver state graph. It can be used to add, remove, insert or replace a graph node. Currently only the Quorum driver implements this feature to add or remove its child. This is useful to fix a broken quorum child.
    
    If node is specified, it will be inserted under parent. child may not be specified in this case. If both parent and child are specified but node is not, child will be detached from parent.
    
    1. Add a new node to a quorum
    -> { "execute": "blockdev-add",
         "arguments": {
             "driver": "raw",
             "node-name": "new_node",
             "file": { "driver": "file",
                       "filename": "test.raw" } } }
    <- { "return": {} }
    -> { "execute": "x-blockdev-change",
         "arguments": { "parent": "disk1",
                        "node": "new_node" } }
    <- { "return": {} }
    
    2. Delete a quorum's node
    -> { "execute": "x-blockdev-change",
         "arguments": { "parent": "disk1",
                        "child": "children.1" } }
    <- { "return": {} }
    
    

    动态修改块设备的层级关系。

    上文说了,在主节点数据盘作为主盘,负责读写,而子盘,NBD客户端只执行写动作,所以一旦子节点离线,则子盘需要移除掉,配置成新的虚拟机NBD客户端。该执行就是来执行这个操作的。

    例如:

    第四个步骤执行的

    {'execute': 'x-blockdev-change', 'arguments':{'parent': 'colo-disk0', 'node': 'replication0' } }
    
    # 将replication0 配置为 colo-disk0的子盘
    

    备份虚拟机挂了,主虚拟机需要执行的操作

    {'execute': 'x-blockdev-change', 'arguments':{ 'parent': 'colo-disk0', 'child': 'children.1'} }
    

    这个children.1是没有用的,根据上文的描述,只指定child不指定node,将会导致原来的子盘与母盘分离。

    所以这个解除上个指令绑定的replication0

补充

2021-09-23

主要是这句话,image
简单来说就是一开始,P虚拟机的磁盘与S的磁盘要一致,hiddenactive 是空盘,这两个空盘是S盘的快照盘(可以这么理解,其实保留的是S盘修改的块,),就是使用写时复制的方法,S虚拟机读取数据时,读取的是S的磁盘数据,写入数据时,使用COW,将S磁盘的块数据复制到active盘进行修改。同时复制到hidden盘记录。hidden 数据块的操作者有两个,一个是P拟机网络转发过来的请求导致数据块的修改,一个是 NBD Server 迁移过来导致的数据修改,这两个最终的结果是一致的,但是顺序是不可控的,因为NBD Server 走的是网络, 转发过来走的也是网络,哪个快,这个是不固定的。 所以如果 hidden的数据块被修改了,说明 转发请求的处理比较快, 这时NBD就没有必要去覆盖了。至于NBD Server处理的比较快,就没办法了,hidden就得写两次,一次是NBD,一次是,转发请求操作系统处理后写入的。操系统作写入是阻止不了的。所以这里,image

步骤4是一定会写入的,步骤6就检查,如果步骤4已经执行了,步骤6就不写入了。 至于activehidden 的盘大小应该可以不跟P,S磁盘大小一样,只要保证 activehidden 一样 大小就可以了,它们保留的都是COW修改的块数据,所以不会很大,取决于两次checkoutpoint 之间的数据差异量。

posted @ 2021-09-30 11:38  Test002  阅读(333)  评论(0)    收藏  举报