OpenStack-Pike版本中的資源管理與並發調度">OpenStack-Pike版本中的資源管理與並發調度

分類:IT技術 時間:2017-10-01

資源以物理機(ComputeNode)為粒度統計和上報,所有的資源都從屬於單個ComputeNode。這樣對於一些共享的外部資源,例如 EBS、neutron的ip個數等,不能很好的管理和調度。每增加一種資源,就要相應的修改對應的ComputeNode代碼進行統計和管理,不利於橫向擴展。調度之間存在並發問題,每個調度服務之間的實時資源視圖不一致,導致調度的目標節點有延後性,不夠準確。

Pike版本的資源管理

Pike版本將資源抽象出來,增加一層資源管理層,並且區分資源提供者ResourceProvider、資源項ResourceClass、資源清單Inventory、資源分配Allocation,它們的對應關系如下:

ResourceProvider資源提供者

資源提供者表明資源的擁有者,單個物理機、EBS集群都是一個ResourceProvider。每個ResourceProvider可以提供數個ResourceClass的資源。例如ComputeNode是一個ResourceProvider,它提供多個ResourceClass,包括VCPU、MEMORY_MB、DISK_GB。EBS集群也是一個ResourceProvider,提供一個ResourceClass叫做Volume。

class ResourceProvider(API_BASE):
    """Represents a mapping to a providers of resources."""

    id = Column(Integer, primary_key=True, nullable=False)
    uuid = Column(String(36), nullable=False)
    name = Column(Unicode(200), nullable=True)
    generation = Column(Integer, default=0)          # 用於解決並發
    can_host = Column(Integer, default=0)            # 當前資源提供者是否可以作為宿主機

ResourceClass資源項

資源項表明當前資源的類型和名稱,供用戶區分不同的資源。它只表明資源的名稱類別,不包含具體的資源數量等信息。每個資源類型包含數量不等的具體資源Inventory,可以由多個ResourceProvider提供。例如,MEMORY_MB這個資源項,每個ComputeNode都提供該項資源。每個MEMORY_MB都有一個對應的Inventory,表明具體的資源數量、超售比、保留值等資源的配置。

class ResourceClass(API_BASE):
    """Represents the type of resource for an inventory or allocation."""
    id = Column(Integer, primary_key=True, nullable=False)
    name = Column(String(255), nullable=False)

Inventory資源詳情

資源詳情表明ResourceClass中的具體資源和一些配置。例如對於某臺ComputeNode作為一個ResourceProvider,提供一項資源MEMORY_MB並且該項資源有一個詳細的描述Inventory。

class Inventory(API_BASE):
    """Represents a quantity of available resource."""

    id = Column(Integer, primary_key=True, nullable=False)
    resource_provider_id = Column(Integer, nullable=False)
    resource_class_id = Column(Integer, nullable=False)
    total = Column(Integer, nullable=False)
    reserved = Column(Integer, nullable=False)            # 保留的資源,例如一臺ComputeNode保留給系統的內存,不用於分配
    min_unit = Column(Integer, nullable=False)            # 分配的最小值,例如VCPUS是1, MEMORY_MB是1024等
    max_unit = Column(Integer, nullable=False)            # 分配的最大值,例如VCPUS是32, MEMORY_MB是128*1024
    step_size = Column(Integer, nullable=False)           # 分配的最小單位,例如MEMORY_MB是1024,只能按照G來分配,不能分配512MB
    allocation_ratio = Column(Float, nullable=False)      # 超售比 實際可分配資源=total * allocation_ratio

Allocation資源分配

資源分配表明一個實例需要的一項資源項ResourceClass的具體數值,以及該項資源分配給誰。例如一個雲主機需要2GB內存,那麽就用一個Allocation表示並單獨記錄在數據庫中,等同於之前版本中的Instance中記錄的一項資源的使用(memory_mb_used)。

class Allocation(API_BASE):
    """A use of inventory."""
    id = Column(Integer, primary_key=True, nullable=False)
    resource_provider_id = Column(Integer, nullable=False)          # 資源提供者
    consumer_id = Column(String(36), nullable=False)                # 資源消耗者
    resource_class_id = Column(Integer, nullable=False)             # 資源名稱
    used = Column(Integer, nullable=False)                          # 具體數值

以上是資源管理的具體分工,它們的對應關系如下:

                    ResourceClass:        CPU                       MEMORY_MB                        DISK_GB
                                           ↓                             ↓                              ↓
ComputeNode -> ResourceProvider ->   Inventory(CPU)               Inventory(MEMORY_MB)             Inventory(DISK_GB)       
                                                                ↙        ↓          ↘
     Instance(2core, 2g, 100disk):   Allocation(MEMORY_MB: 2G)           ↓             ↘         
     Instance(4core, 4g, 200disk):                             Allocation(MEMORY_MB: 4G) ↘   
     Instance(2core, 4g, 100Disk):                                                        Allocation(MEMORY_MB: 4G)

MEMORY_MB: 8G used

這樣ComputeNode只是作為所有資源中的一個ResourceProvider,所有的資源提供者都是作為平等的ResourceProvider參與調度和資源管理,並且支持動態添加資源類型。

2.並發調度

之前的並發調度

之前的版本中多個調度節點之間沒有同步機制,每個調度節點每次調度時直接從數據庫獲取資源視圖,計算匹配的目標,這樣導致各個節點之間資源視圖不能及時更新,有延後性。只能通過CompudeNode中ResourceTracker的資源鎖和rescheduler來保證資源的最終一致。

Pike並發調度

在新的資源管理下,調度成功後會將消耗的資源記為一個Allocation並寫入數據庫,在寫入數據庫時利用’compare and update’策略實現同步,保證只有在有資源的情況下Alloction才更新成功,選擇的目標才有效。原理如下。

deadlock_retry:

    $ID, $GENERATION = SELECT id, generation FROM resource_providers
                       WHERE ( <QUERY_TO_IDENTIFY_AVAILABLE_INVENTORY> );

    BEGIN TRANSACTION;
    FOR $RESOURCE_CLASS, $REQUESTED_AMOUNT IN requested_resources:
        INSERT INTO allocations (
            resource_provider_id,
            resource_class_id,
            consumer_id,
            used
        ) VALUES (
            $RESOURCE_PROVIDER_ID,
            $RESOURCE_CLASS,
            $INSTANCE_UUID,
            $REQUESTED_AMOUNT
        );
    $ROWS_AFFECTED = UPDATE resource_providers
                     SET generation = $GENERATION + 1
                     WHERE generation = $GENERATION;
    IF $ROWS_AFFECTED == 0:
        ROLLBACK TRANSACTION;
        GO TO deadlock_retry;
    COMMIT TRANSACTION;

通過事物保證每次Allocation的數據庫操作的原子性。獲取資源視圖和更新資源視圖時,通過generation來保證資源一致。總的調度邏輯如下:

HOST = []
FOR $RESOUCE_CLASS, $REQUEST_ALLOCATION FOR REQUESTED_RESOUCES:
    GET $RESOUCES_PROVIDERS, $GENERATION FOR $RESOUCE_CLASS
    GET $INVENTORY AND $ALLOCATIONS FOR RESOUCE_CLASS AND RESOUCE_PROVIDER
    IF $INVENTORY["total"] - sum($ALLOCATIONS["used"] >= REQUEST_ALLCOATION:
        $HOST.append($RESOURCE_PROVIDER)


FILTER $HOSTS
WEIGHT $HOSTS


FOR $HOST IN $HOSTS:
    IF (UPDATE ALLOCATION SUCCESS):
        SELECTED $HOST; return
    else:
        ROLLBACK ALLOCATION;


IF NO $HOST SELCETED:
    RAISE NoVildHost

(完)


Tags: 資源 ResourceProvider 調度 提供者 ResourceClass quot

文章來源:


ads
ads

相關文章
ads

相關文章

ad