日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分布式块存储QoS限速算法介绍与实践以及对上层应用的影响

發布時間:2024/2/28 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分布式块存储QoS限速算法介绍与实践以及对上层应用的影响 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

分布式塊存儲QoS限速算法以及對上層應用的影響

    • QoS限速算法介紹
      • 令牌桶 Token Bucket
      • 漏桶 Leaky Bucket
        • Leaky bucket as a meter
        • Leaky bucket as a queue
    • 主流的塊設備流控方案
      • Qemu
      • librbd
      • spdk
    • 限速策略對塊設備的影響
      • 時延
      • IO util
      • 對數據庫應用的影響
    • 參考鏈接


QoS限速算法介紹

限速策略主要有令牌桶的漏桶兩種,下面分別介紹如下。

令牌桶 Token Bucket

Wiki對令牌桶的算法描述如下:

  • A token is added to the bucket every 1/r seconds.
  • The bucket can hold at the most b tokens. If a token arrives when the bucket is full, it is discarded.
  • When a packet (network layer PDU) of n bytes arrives,
    • if at least n tokens are in the bucket, n tokens are removed from the bucket, and the packet is sent to the network.
    • if fewer than n tokens are available, no tokens are removed from the bucket, and the packet is considered to be non-conformant.

一個固定容量的桶裝著一定數量的令牌,桶的容量即令牌數量上限。桶里的令牌數量會每隔固定時間補充,直到桶被裝滿。一個IO請求將消耗一個令牌,如果桶里有令牌,則該IO請求消耗令牌后放行,反之則無法放行(算法可以選擇是否放棄IO請求)。如果對字節數限流,每次個IO會消耗iosize大小的令牌。

按照以上描述,我們可以知道,令牌桶算法可以達到以下效果:

  • 令牌桶算法可以通過控制令牌補充速率來控制處理IO請求的速率;
  • 令牌桶算法允許一定程度的突發,只要桶里的令牌沒有耗盡,IO請求即可立即消耗令牌并放行,這段時間內IO請求處理速率將大于令牌補充速率,令牌補充速率實際為平均處理速率;
  • 令牌桶算法無法控制突發速率上限和突發時長,突發時長由實際IO請求速率決定,若實際IO請求大于令牌補充速率且速率恒定,則:突發時長=令牌桶容量/(實際IO請求速率-令牌補充速率)
  • 漏桶 Leaky Bucket

    Leaky bucket as a meter

    Wiki中對Leaky bucket as a meter定義如下:

    • A fixed capacity bucket, associated with each virtual connection or user, leaks at a fixed rate.
    • If the bucket is empty, it stops leaking.
    • For a packet to conform, it has to be possible to add a specific amount of water to the bucket: The specific amount added by a conforming packet can be the same for all packets, or can be proportional to the length of the packet.
    • If this amount of water would cause the bucket to exceed its capacity then the packet does not conform and the water in the bucket is left unchanged.

    我們可以理解如下:

    一個桶,以固定的流量漏水,經過的IO會請求報文會向桶中加水,加水的量以流控的方面為準,可以是byte,可以是IOPS,如果加水溢出,則IO不能通過,反之則可以放行。

    可見,這個算法描述和令牌桶基本類似,我們可以認為Leaky bucket as a meter和Token Bucket是等價的。

    Leaky bucket as a queue

    wiki對這種限流策略的描述是:The leaky bucket consists of a finite queue. When a packet arrives, if there is room on the queue it is appended to the queue; otherwise it is discarded. At every clock tick one packet is transmitted (unless the queue is empty)

    可以認為,Leaky bucket as a queue就是令牌桶的桶大小等于1的場景。

    主流的塊設備流控方案

    主流的、在工程上有大范圍應用的留空策略,主要有三種,qemu,librbd,spdk,下面分別介紹

    Qemu

    Qemu早在1.1版本就已支持塊設備IO限速,提供6個配置項,可對IOPS和帶寬6種場景分別進行速率上限設置。在1.7版本對塊設備IO限速增加了支持突發的功能。在2.6版本對支持突發的功能進行了完善,可控制突發速率和時長。參數如下:

    場景基本速率上限配置突發速率配置突發時長配置
    總iopsiops-totaliops-total-maxiops-total-max-length
    讀iopsiops-readiops-read-maxiops-read-max-length
    寫iopsiops-writeiops-write-maxiops-write-max-length
    總bpsbps-totalbps-total-maxbps-total-max-length
    讀bpsbps-readbps-read-maxbps-read-max-length
    寫bpsbps-writebps-write-maxbps-write-max-length

    其實現的核心數據結構是這樣描述的:

    typedef struct LeakyBucket {uint64_t avg; /* IO的限制目標速率 */uint64_t max; /* IO的突發限制速率 */double level; /* bucket level in units */double burst_level; /* bucket level in units (for computing bursts) */uint64_t burst_length; /* 突發時長,默認單位是秒 */ } LeakyBucket

    Qemu的流控算法使用漏桶實現。算法的的目標是,用戶可以在突發速率bkt.max持續bkt.burst_length秒,之后速率會降為bkt.avg

    為了實現這個目標,qemu實現了兩個桶

  • 主桶:大小bucket_size為bkt.max * bkt.burst_length,以bkt.avg的速率漏水,正常IO先經過主桶處理
  • 突發桶:大小burst_bucket_size設置為主桶的十分之一,以bkt.max速率漏水
  • 如果主桶已經滿了,則需要等待漏桶,如果主桶未滿并且設置了突發桶,則需要檢驗突發桶是否可以放行。這樣,我們通過突發桶保證了IO的突發速率,通過主桶的大小,保證了突發的時間。

    關鍵的控制IO是否能放行的函數如下:

    /* This function compute the wait time in ns that a leaky bucket should trigger** @bkt: the leaky bucket we operate on* @ret: the resulting wait time in ns or 0 if the operation can go through*/ int64_t throttle_compute_wait(LeakyBucket *bkt) {double extra; /* the number of extra units blocking the io */double bucket_size; /* I/O before throttling to bkt->avg */double burst_bucket_size; /* Before throttling to bkt->max */if (!bkt->avg) {return 0;}if (!bkt->max) {/* If bkt->max is 0 we still want to allow short bursts of I/O* from the guest, otherwise every other request will be throttled* and performance will suffer considerably. */bucket_size = (double) bkt->avg / 10;burst_bucket_size = 0;} else {/* If we have a burst limit then we have to wait until all I/O* at burst rate has finished before throttling to bkt->avg */bucket_size = bkt->max * bkt->burst_length;burst_bucket_size = (double) bkt->max / 10;}/* If the main bucket is full then we have to wait */extra = bkt->level - bucket_size;if (extra > 0) {return throttle_do_compute_wait(bkt->avg, extra);}/* If the main bucket is not full yet we still have to check the* burst bucket in order to enforce the burst limit */if (bkt->burst_length > 1) {assert(bkt->max > 0); /* see throttle_is_valid() */extra = bkt->burst_level - burst_bucket_size;if (extra > 0) {return throttle_do_compute_wait(bkt->max, extra);}}return 0; }

    librbd

    Ceph在13.2.0版本(m版)支持對RBD鏡像的IO限速,此版本僅支持總iops場景的限速,且支持突發,支持配置突發速率,但不可控制突發時長(實際相當于突發時長設置為1秒且無法修改)。在14.2.0版本(n版)增加了對讀iops、寫iops、總bps、讀bps、寫bps這5種場景的限速支持,對突發的支持效果保持不變。

    Librbd的限速機制支持突發,支持配置突發速率,但不支持控制突發時長,使用令牌桶實現。令牌桶加水的速率可以使用rbd_qos_schedule_tick_min參數調節,默認50ms,用戶可以通過如下參數配置基本速率和突發速率。

    場景基本速率上限配置突發速率配置
    總iopsrbd_qos_iops_limitrbd_qos_iops_burst
    讀iopsrbd_qos_iops_read_limitrbd_qos_iops_read_burst
    寫iopsrbd_qos_iops_write_limitrbd_qos_iops_write_burst
    總bpsrbd_qos_bps_limitrbd_qos_bps_burst
    讀bpsrbd_qos_bps_read_limitrbd_qos_bps_read_burst
    寫bpsrbd_qos_bps_write_limitrbd_qos_bps_write_burst

    spdk

    spdk的qos限速實現在bdev層,是令牌桶。支持對IOPS和BW單獨進行配置,但是不支持突發速率。通過使用rpc請求bdev_set_qos_limit進行配置。配置參數如下

    參數解釋
    rw_ios_per_secIOPS限制
    rw_mbytes_per_sec讀寫帶寬限制
    r_mbytes_per_sec讀帶寬限制
    w_mbytes_per_sec寫帶寬限制

    spdk通過注冊poller函數bdev_channel_poll_qos向令牌桶中加令牌,頻率為SPDK_BDEV_QOS_TIMESLICE_IN_USEC硬編碼,默認1ms。每次加令牌的頻率就是總速率/時間片

    一個IO需要經過所有配置的令牌桶之后才可以被放行,令牌桶可以單次消耗減為負數,減為負數之后所有的IO均不能被放行,只有等函數bdev_channel_poll_qos重新將令牌桶加成正數之后才能放行。

    static int bdev_channel_poll_qos(void *arg) {struct spdk_bdev_qos *qos = arg;uint64_t now = spdk_get_ticks();int i;if (now < (qos->last_timeslice + qos->timeslice_size)) {/* We received our callback earlier than expected - return* immediately and wait to do accounting until at least one* timeslice has actually expired. This should never happen* with a well-behaved timer implementation.*/return SPDK_POLLER_IDLE;}/* Reset for next round of rate limiting */for (i = 0; i < SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES; i++) {/* We may have allowed the IOs or bytes to slightly overrun in the last* timeslice. remaining_this_timeslice is signed, so if it's negative* here, we'll account for the overrun so that the next timeslice will* be appropriately reduced.*/if (qos->rate_limits[i].remaining_this_timeslice > 0) {qos->rate_limits[i].remaining_this_timeslice = 0;}}while (now >= (qos->last_timeslice + qos->timeslice_size)) {qos->last_timeslice += qos->timeslice_size;for (i = 0; i < SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES; i++) {qos->rate_limits[i].remaining_this_timeslice +=qos->rate_limits[i].max_per_timeslice;}}return bdev_qos_io_submit(qos->ch, qos); }

    限速策略對塊設備的影響

    不同的qos策略上層塊設備的體驗也是不同的,主要體現在IO的時延和%util。

    時延

    時延由qos策略的突發性能和補充頻率決定

    • 突發性能,設置比較大的漏桶或令牌桶,或者像Qemu那樣配置兩個桶,可以增強塊設備的突發性能,讓塊設備承受突發流量時延時比較低。
      • 可以通過fio命令fio --group_reporting --rw=randwrite --bs=1M --numjobs=1 --iodepth=64 --ioengine=libaio --direct=1 --name test --size=2000G --filename=/dev/vdb -iodepth_low=0 -iodepth_batch_submit=64 -thinktime=950ms -thinktime_blocks=64,每次下發1M隊列深度為64的IO,下發完成之后等950ms再重復。如果塊設備的突發性能不行,看到的現象是iowait時延較大,時延與隊列深度呈線性增長,且帶寬壓不上去。而且因為我們每次IO下發都會等很久,因此io util也不高。
    • 補充頻率,補充頻率較低會造成拖尾時延嚴重,舉個簡單的例子,令牌桶每隔1秒補充一次,那么如果當前這1秒下發的IO下過了限制,那么有些IO的時延肯定會超過1秒,造成拖尾時延較大。

    IO util

    磁盤util值定義為磁盤處理IO時間占總時間的比例。也就是當前磁盤隊列中有IO的時間和總時間的比率。如果限速算法導致處理IO的時間分布很均勻(如Leaky bucket as a queue,IO一個個斷續的被處理),磁盤隊列一直存在IO,那么util自然較高。

    而設置突發性能較大的塊設備,很高的隊列深度也可以被很快的處理完成,Util自然低。

    對數據庫應用的影響

    我們這里以構建于分布式塊設備之上的數據庫mysql為例,談談限速策略對sql性能造成的影響。

    在mysql中,主要有兩部分IO比較影響性能

  • 下刷臟頁
  • mysql為了減少IO數量,提高讀寫性能,引入了buffer pool,mysql對數據的修改會首先修改到buffer pool中,等到合適的實際時間下刷。當內存數據頁跟磁盤數據頁內容不一致的時候,我們稱這個內存頁為“臟頁”。內存數據寫入到磁盤后,內存和磁盤上的數據頁的內容就一致了,稱為“干凈頁”。
  • 從使用場景上我們可以推斷,每次下刷臟頁必然是大IO高隊列,如果塊設備突發性能不行,會導致下刷臟頁速率慢,并且如上所述,這種場景極有可能ioutil不高。也就是說這種IO模型并沒有發揮限流機制的性能。
  • 解決方法也很簡單:
  • 降低隊列深度(每次下刷臟頁的大小),以抵消突發性能不足的限制
  • 加快下刷頻率,從而提高ioutil,提高對限流策略的利用率。
  • 下刷redo-log。這里不談bin-log是因為官方認為開啟bin-log的性能損耗小于1%
  • redo-log為了保證正確性,是單線程順序寫的,如果塊設備的突發性能不行,會導致下發redo-log的時延較高,拖累整個系統的TPS。
  • redo-log如果和其他IO共享同一塊盤,redo-log自身的優先級無法體現,有可能因為臟頁下刷觸發了限流,而增大了redo-log的時延。
  • 解決方法有以下幾種:
  • 增加塊設備的突發能力
  • 提升redo-log的優先級,讓redo-log先下發,如果塊設備系統不支持IO優先級,可以另外申請一塊盤作為redo-log盤單獨使用。
  • 上層mysql應用支持并發隨機寫的redo-log(PolarDB應該已經實現了)。
  • 參考鏈接

  • Wiki Token bucket
  • Wiki Leaky bucket
  • 令牌桶 限速_Qemu與Librbd的QoS限速機制比較與算法剖析
  • 寫在工作10周年
  • qemu leaky bucket
  • 華為云盤EVS突發能力介紹
  • 怎樣測試云硬盤的性能
  • 壓測ESSD云盤IOPS性能
  • 總結

    以上是生活随笔為你收集整理的分布式块存储QoS限速算法介绍与实践以及对上层应用的影响的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。