91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

victoriaMetrics庫布隆過濾器初始化及使用的方法

發布時間:2022-04-06 10:19:51 來源:億速云 閱讀:268 作者:iii 欄目:開發技術

本篇內容主要講解“victoriaMetrics庫布隆過濾器初始化及使用的方法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“victoriaMetrics庫布隆過濾器初始化及使用的方法”吧!

victoriaMetrics庫布隆過濾器

概述

victoriaMetrics的vmstorage組件會接收上游傳遞過來的指標,在現實場景中,指標或瞬時指標的數量級可能會非常恐怖,如果不限制緩存的大小,有可能會由于cache miss而導致出現過高的slow insert。

為此,vmstorage提供了兩個參數:maxHourlySeriesmaxDailySeries,用于限制每小時/每天添加到緩存的唯一序列。

唯一序列指表示唯一的時間序列,如metrics{label1="value1",label2="value2"}屬于一個時間序列,但多條不同值的metrics{label1="value1",label2="value2"}屬于同一條時間序列。victoriaMetrics使用如下方式來獲取時序的唯一標識:

func getLabelsHash(labels []prompbmarshal.Label) uint64 {
	bb := labelsHashBufPool.Get()
	b := bb.B[:0]
	for _, label := range labels {
		b = append(b, label.Name...)
		b = append(b, label.Value...)
	}
	h := xxhash.Sum64(b)
	bb.B = b
	labelsHashBufPool.Put(bb)
	return h
}

限速器的初始化

victoriaMetrics使用了一個類似限速器的概念,限制每小時/每天新增的唯一序列,但與普通的限速器不同的是,它需要在序列級別進行限制,即判斷某個序列是否是新的唯一序列,如果是,則需要進一步判斷一段時間內緩存中新的時序數目是否超過限制,而不是簡單地在請求層面進行限制。

hourlySeriesLimiter = bloomfilter.NewLimiter(*maxHourlySeries, time.Hour)
dailySeriesLimiter = bloomfilter.NewLimiter(*maxDailySeries, 24*time.Hour)

下面是新建限速器的函數,傳入一個最大(序列)值,以及一個刷新時間。該函數中會:

  • 初始化一個限速器,限速器的最大元素個數為maxItems

  • 則啟用了一個goroutine,當時間達到refreshInterval時會重置限速器

func NewLimiter(maxItems int, refreshInterval time.Duration) *Limiter {
	l := &Limiter{
		maxItems: maxItems,
		stopCh:   make(chan struct{}),
	}
	l.v.Store(newLimiter(maxItems)) //1
	l.wg.Add(1)
	go func() {
		defer l.wg.Done()
		t := time.NewTicker(refreshInterval)
		defer t.Stop()
		for {
			select {
			case <-t.C:
				l.v.Store(newLimiter(maxItems))//2
			case <-l.stopCh:
				return
			}
		}
	}()
	return l
}

限速器只有一個核心函數Add,當vmstorage接收到一個指標之后,會(通過getLabelsHash計算該指標的唯一標識(h),然后調用下面的Add函數來判斷該唯一標識是否存在于緩存中。

如果當前存儲的元素個數大于等于允許的最大元素,則通過過濾器判斷緩存中是否已經存在該元素;否則將該元素直接加入過濾器中,后續允許將該元素加入到緩存中。

func (l *Limiter) Add(h uint64) bool {
	lm := l.v.Load().(*limiter)
	return lm.Add(h)
}
func (l *limiter) Add(h uint64) bool {
	currentItems := atomic.LoadUint64(&l.currentItems)
	if currentItems >= uint64(l.f.maxItems) {
		return l.f.Has(h)
	}
	if l.f.Add(h) {
		atomic.AddUint64(&l.currentItems, 1)
	}
	return true
}

上面的過濾器采用的是布隆過濾器,核心函數為HasAdd,分別用于判斷某個元素是否存在于過濾器中,以及將元素添加到布隆過濾器中。

過濾器的初始化函數如下,bitsPerItem是個常量,值為16。bitsCount統計了過濾器中的總bit數,每個bit表示某個值的存在性。bits以64bit為單位的(后續稱之為slot,目的是為了在bitsCount中快速檢索目標bit)。計算bits時加上63的原因是為了四舍五入向上取值,比如當maxItems=1時至少需要1個unit64的slot。

func newFilter(maxItems int) *filter {
	bitsCount := maxItems * bitsPerItem
	bits := make([]uint64, (bitsCount+63)/64)
	return &filter{
		maxItems: maxItems,
		bits:     bits,
	}
}

為什么bitsPerItem為16?這篇文章給出了如何計算布隆過濾器的大小。在本代碼中,k為4(hashesCount),期望的漏失率為0.003(可以從官方的filter_test.go中看出),則要求總存儲和總元素的比例為15,為了方便檢索slot(64bit,為16的倍數),將之設置為16。

	if p &gt; 0.003 {
		t.Fatalf("too big false hits share for maxItems=%d: %.5f, falseHits: %d", maxItems, p, falseHits)
	}

victoriaMetrics庫布隆過濾器初始化及使用的方法

下面是過濾器的Add操作,目的是在過濾器中添加某個元素。Add函數中沒有使用多個哈希函數來計算元素的哈希值,轉而改變同一個元素的值,然后對相應的值應用相同的哈希函數,元素改變的次數受hashesCount的限制。

  • 獲取過濾器的完整存儲,并轉換為以bit單位

  • 將元素h轉換為byte數組,便于xxhash.Sum64計算

  • 后續將執行hashesCount次哈希,降低漏失率

  • 計算元素h的哈希

  • 遞增元素h,為下一次哈希做準備

  • 取余法獲取元素的bit范圍

  • 獲取元素所在的slot(即uint64大小的bit范圍)

  • 獲取元素所在的slot中的bit位,該位為1表示該元素存在,為0表示該元素不存在

  • 獲取元素所在bit位的掩碼

  • 加載元素所在的slot的數值

  • 如果w & mask結果為0,說明該元素不存在,

  • 將元素所在的slot(w)中的元素所在的bit位(mask)置為1,表示添加了該元素

  • 由于Add函數可以并發訪問,因此bits[i]有可能被其他操作修改,因此需要通過重新加載(14)并通過循環來在bits[i]中設置該元素的存在性

func (f *filter) Add(h uint64) bool {
	bits := f.bits
	maxBits := uint64(len(bits)) * 64 //1
	bp := (*[8]byte)(unsafe.Pointer(&h))//2
	b := bp[:]
	isNew := false
	for i := 0; i < hashesCount; i++ {//3
		hi := xxhash.Sum64(b)//4
		h++ //5
		idx := hi % maxBits //6
		i := idx / 64 //7
		j := idx % 64 //8
		mask := uint64(1) << j //9
		w := atomic.LoadUint64(&bits[i])//10
		for (w & mask) == 0 {//11
			wNew := w | mask //12
			if atomic.CompareAndSwapUint64(&bits[i], w, wNew) {//13
				isNew = true//14
				break
			}
			w = atomic.LoadUint64(&bits[i])//14
		}
	}
	return isNew
}

看懂了Add函數,Has就相當簡單了,它只是Add函數的縮減版,無需設置bits[i]

func (f *filter) Has(h uint64) bool {
	bits := f.bits
	maxBits := uint64(len(bits)) * 64
	bp := (*[8]byte)(unsafe.Pointer(&h))
	b := bp[:]
	for i := 0; i < hashesCount; i++ {
		hi := xxhash.Sum64(b)
		h++
		idx := hi % maxBits
		i := idx / 64
		j := idx % 64
		mask := uint64(1) << j
		w := atomic.LoadUint64(&bits[i])
		if (w & mask) == 0 {
			return false
		}
	}
	return true
}

到此,相信大家對“victoriaMetrics庫布隆過濾器初始化及使用的方法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

运城市| 喀喇沁旗| 利辛县| 大庆市| 象山县| 涞源县| 织金县| 沙河市| 监利县| 保定市| 临颍县| 通许县| 桑日县| 邢台县| 临江市| 和平县| 米易县| 泾川县| 昌宁县| 江安县| 工布江达县| 普洱| 阿拉尔市| 康保县| 沙湾县| 襄樊市| 诏安县| 岳普湖县| 德阳市| 孙吴县| 北安市| 青河县| 汤阴县| 基隆市| 阳谷县| 石家庄市| 永靖县| 通河县| 自治县| 郎溪县| 双牌县|