首頁  >  文章  >  後端開發  >  我運行 2 個 goroutine 來修改虛擬機器並在同一實例上使用 libvirt-go 套件銷毀同一虛擬機會發生什麼?

我運行 2 個 goroutine 來修改虛擬機器並在同一實例上使用 libvirt-go 套件銷毀同一虛擬機會發生什麼?

王林
王林轉載
2024-02-08 21:48:121084瀏覽

我运行 2 个 goroutine 来修改虚拟机并在同一实例上使用 libvirt-go 包销毁同一虚拟机会发生什么?

php小編魚仔你提到的問題涉及在同一實例上同時使用libvirt-go包銷毀虛擬機器的情況。在這種情況下,會出現兩個goroutine同時修改虛擬機器的情況,可能會導致不可預料的結果。由於goroutine在並發執行時無法保證執行順序,可能會導致競態條件或資料衝突,進而導致虛擬機器銷毀失敗、資料損壞或其他異常情況。為了避免這種情況,可以透過使用互斥鎖或其他並發控制機制來確保同時只有一個goroutine可以修改虛擬機器。這樣可以確保操作的原子性和一致性,避免不必要的問題發生。

問題內容

眾所周知,libvirt 是執行緒安全的。 但是,同時執行兩個作用於相同資源的 goroutine(例如修改和刪除虛擬機器)會使其處於不明確的狀態。 libvirt 如何決定 goroutine 的執行順序?

這是我嘗試過的程式碼:

package main

import (
    "fmt"

    "github.com/libvirt/libvirt-go"
)

func main() {
    conn, err := libvirt.NewConnect("qemu:///system")
    if err != nil {
        fmt.Printf("Failed to connect to libvirt: %v\n", err)
        return
    }
    defer conn.Close()

    // Create a new VM
    domainXML := `
        <domain type='kvm'>
            <name>myvm</name>
            <memory unit='KiB'>1048576</memory>
            <vcpu placement='static'>1</vcpu>
            <os>
                <type arch='x86_64' machine='pc-i440fx-2.9'>hvm</type>
                <boot dev='hd'/>
            </os>
            <devices>
                <disk type='file' device='disk'>
                    <driver name='qemu' type='qcow2'/>
                    <source file='path/to/disk'/>
                    <target dev='vda' bus='virtio'/>
                    <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
                </disk>
            </devices>
        </domain>`

    dom, err := createVM(conn, domainXML)
    if err != nil {
        fmt.Printf("Failed to create VM: %v\n", err)
        return
    }

    go modifyVMMemory(dom, 2*1024*1024) // 2 GiB

    go deleteVM(dom)

}

func createVM(conn *libvirt.Connect, domainXML string) (*libvirt.Domain, error) {
    dom, err := conn.DomainCreateXML(domainXML, 0)
    if err != nil {
        return nil, err
    }
    return dom, nil
}

func modifyVMMemory(dom *libvirt.Domain, newMemory uint64) error {
    err := dom.SetMaxMemory(newMemory)
    if err != nil {
        return err
    }
    fmt.Print("Modified VM")
    return nil
}

func deleteVM(dom *libvirt.Domain) error {
    err := dom.Destroy()
    if err != nil {
        return err
    }

    err = dom.Undefine()
    if err != nil {
        return err
    }

    fmt.Print("Deleted VM")

    return nil
}

程式成功完成,因此網域被破壞並可以重新創建 但再次運行會導致以下錯誤:

virError(Code=9, Domain=20, Message='operation failed: domain 'myvm' already exists with uuid 32c25acb-a4c5-4bfd-b2f5-f07b3d9b8eea')

解決方法

線程安全性只是意味著當多個線程同時使用同一個連接時,程式碼不會出現記憶體損壞問題。

您將獲得的語意行為仍然是不確定的。

libvirt QEMU/KVM 驅動程式在用戶端應用程式和 libvirtd(或 virtqemud)守護程式之間使用 RPC 層。所以首先你有非確定性,其中 Goroutine 首先運行。當libvirt-go-module API 透過CGo 呼叫C ibvirt.so 函式庫時,它們將被鎖定到本機作業系統線程,然後該線程將在libvirt. so 內部同步,以決定哪一個首先將其RPC 訊息傳送到網路上。在libvirtd 守護程式中,也有很多線程,而RPC 訊息理論上是FIFO 處理的,但是,libvirtd 內部的API 邏輯仍然會爭奪鎖,因此在與QEMU 通訊/互動時會增加更多的不確定性。基本上,您的 SetMaxMemoryDestroy API 呼叫可以任一順序運行。如果您需要保證順序,則需要在應用程式中對它們進行序列化,以便僅在完成 SetMaxMemory 後呼叫 Destroy

最後 IIUC 你的 Go 程式碼並不健壯,因為 main() 方法產生了兩個 goroutine,但沒有等待它們中的任何一個完成。 IOW,在任一 goroutine 完全運行之前,Go 進程很可能會退出。這可能是為什麼您收到有關 VM 已存在的錯誤訊息的原因 - deleteVM goroutine 在進程退出之前從未運行。

以上是我運行 2 個 goroutine 來修改虛擬機器並在同一實例上使用 libvirt-go 套件銷毀同一虛擬機會發生什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除