ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ฉันขอแนะนำให้คุณอ่านสำเนารายงานปลายปี 2019 โดย Alexander Valyalkin “Go Optimizations in VictoriaMetrics”

วิคตอเรียเมตริกส์ — DBMS ที่รวดเร็วและปรับขนาดได้สำหรับการจัดเก็บและประมวลผลข้อมูลในรูปแบบของอนุกรมเวลา (บันทึกจะสร้างเวลาและชุดของค่าที่สอดคล้องกับเวลานี้ เช่น ได้รับจากการสำรวจสถานะของเซ็นเซอร์หรือการรวบรวมเป็นระยะ เมตริก)

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

นี่คือลิงค์ไปยังวิดีโอของรายงานนี้ - https://youtu.be/MZ5P21j_HLE

สไลด์

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

บอกเราเกี่ยวกับตัวคุณ. ฉันคืออเล็กซานเดอร์ วัลยาลคิน ที่นี่ บัญชี GitHub ของฉัน. ฉันหลงใหลเกี่ยวกับ Go และการเพิ่มประสิทธิภาพการทำงาน ฉันเขียนห้องสมุดที่มีประโยชน์มากมายและไม่มีประโยชน์มากนัก พวกเขาเริ่มต้นด้วยอย่างใดอย่างหนึ่ง fastหรือกับ quick คำนำหน้า

ขณะนี้ฉันกำลังทำงานกับ VictoriaMetrics มันคืออะไรและฉันกำลังทำอะไรอยู่ที่นั่น? ฉันจะพูดถึงเรื่องนี้ในการนำเสนอนี้

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

โครงร่างของรายงานมีดังนี้:

  • ก่อนอื่น ฉันจะบอกคุณว่า VictoriaMetrics คืออะไร
  • แล้วฉันจะบอกคุณว่าอนุกรมเวลาคืออะไร
  • จากนั้นฉันจะบอกคุณว่าฐานข้อมูลอนุกรมเวลาทำงานอย่างไร
  • ต่อไป ฉันจะบอกคุณเกี่ยวกับสถาปัตยกรรมฐานข้อมูล: มันประกอบด้วยอะไรบ้าง
  • จากนั้นเรามาดูการเพิ่มประสิทธิภาพที่ VictoriaMetrics มีกันดีกว่า นี่คือการปรับให้เหมาะสมสำหรับดัชนีกลับด้านและการเพิ่มประสิทธิภาพสำหรับการใช้งานบิตเซ็ตใน Go

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

มีใครในกลุ่มผู้ชมทราบบ้างว่า VictoriaMetrics คืออะไร? ว้าว มีคนรู้เยอะแล้ว มันเป็นข่าวดี สำหรับผู้ที่ไม่ทราบ นี่คือฐานข้อมูลอนุกรมเวลา มันขึ้นอยู่กับสถาปัตยกรรม ClickHouse ในรายละเอียดบางอย่างของการใช้งาน ClickHouse ตัวอย่างเช่น ใน MergeTree การคำนวณแบบขนานบนแกนประมวลผลที่มีอยู่ทั้งหมด และการเพิ่มประสิทธิภาพการทำงานโดยการทำงานกับบล็อกข้อมูลที่วางอยู่ในแคชของโปรเซสเซอร์

VictoriaMetrics ให้การบีบอัดข้อมูลที่ดีกว่าฐานข้อมูลอนุกรมเวลาอื่นๆ

มันปรับขนาดในแนวตั้ง - นั่นคือคุณสามารถเพิ่มโปรเซสเซอร์และ RAM ได้มากขึ้นในคอมพิวเตอร์เครื่องเดียว VictoriaMetrics จะใช้ทรัพยากรที่มีอยู่เหล่านี้ได้สำเร็จ และจะปรับปรุงประสิทธิภาพการผลิตเชิงเส้น

นอกจากนี้ VictoriaMetrics ยังปรับขนาดในแนวนอน กล่าวคือ คุณสามารถเพิ่มโหนดเพิ่มเติมให้กับคลัสเตอร์ VictoriaMetrics ได้ และประสิทธิภาพของคลัสเตอร์จะเพิ่มขึ้นเกือบเป็นเส้นตรง

อย่างที่คุณเดาได้ VictoriaMetrics เป็นฐานข้อมูลที่รวดเร็ว เพราะฉันไม่สามารถเขียนฐานข้อมูลอื่นได้ และมันเขียนด้วยภาษา Go ดังนั้นฉันจึงพูดถึงมันในงานมีตติ้งครั้งนี้

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ใครรู้บ้างว่าอนุกรมเวลาคืออะไร? เขายังรู้จักผู้คนมากมาย อนุกรมเวลาคืออนุกรมของคู่ (timestamp, значение)โดยที่คู่เหล่านี้จะถูกจัดเรียงตามเวลา ค่าเป็นตัวเลขทศนิยม – float64

แต่ละอนุกรมเวลาจะถูกระบุโดยไม่ซ้ำกันด้วยคีย์ คีย์นี้ประกอบด้วยอะไรบ้าง? ประกอบด้วยชุดคู่คีย์-ค่าที่ไม่ว่างเปล่า

นี่คือตัวอย่างอนุกรมเวลา กุญแจสำคัญของซีรีส์นี้คือรายการคู่: __name__="cpu_usage" เป็นชื่อของหน่วยเมตริก instance="my-server" - นี่คือคอมพิวเตอร์ที่รวบรวมการวัดนี้ datacenter="us-east" - นี่คือศูนย์ข้อมูลที่คอมพิวเตอร์เครื่องนี้ตั้งอยู่

เราลงเอยด้วยชื่ออนุกรมเวลาซึ่งประกอบด้วยคู่คีย์-ค่าสามคู่ คีย์นี้สอดคล้องกับรายการคู่ (timestamp, value). t1, t3, t3, ..., tN - นี่คือการประทับเวลา 10, 20, 12, ..., 15 — ค่าที่สอดคล้องกัน นี่คือการใช้งาน CPU ในช่วงเวลาที่กำหนดสำหรับซีรีส์ที่กำหนด

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

อนุกรมเวลาสามารถใช้ได้ที่ไหน? ไม่มีใครมีความคิดใด ๆ ?

  • ใน DevOps คุณสามารถวัด CPU, RAM, เครือข่าย, rps, จำนวนข้อผิดพลาด ฯลฯ
  • IoT - เราสามารถวัดอุณหภูมิ ความดัน พิกัดทางภูมิศาสตร์ และอื่นๆ ได้
  • รวมถึงการเงินด้วย – เราสามารถตรวจสอบราคาของหุ้นและสกุลเงินทุกประเภทได้
  • นอกจากนี้ยังสามารถใช้อนุกรมเวลาในการติดตามกระบวนการผลิตในโรงงานได้อีกด้วย เรามีผู้ใช้ที่ใช้ VictoriaMetrics ในการตรวจสอบกังหันลมสำหรับหุ่นยนต์
  • อนุกรมเวลายังมีประโยชน์ในการรวบรวมข้อมูลจากเซ็นเซอร์ของอุปกรณ์ต่างๆ ตัวอย่างเช่น สำหรับเครื่องยนต์ สำหรับวัดแรงดันลมยาง สำหรับวัดความเร็ว ระยะทาง สำหรับวัดปริมาณการใช้น้ำมันเบนซิน ฯลฯ
  • อนุกรมเวลายังสามารถใช้เพื่อตรวจสอบเครื่องบินได้ เครื่องบินแต่ละลำจะมีกล่องดำที่รวบรวมอนุกรมเวลาสำหรับพารามิเตอร์ต่างๆ ด้านสุขภาพของเครื่องบิน อนุกรมเวลายังใช้ในอุตสาหกรรมการบินและอวกาศอีกด้วย
  • การดูแลสุขภาพ ได้แก่ ความดันโลหิต ชีพจร ฯลฯ

อาจมีแอปพลิเคชันอื่น ๆ ที่ฉันลืมไป แต่ฉันหวังว่าคุณจะเข้าใจว่าอนุกรมเวลามีการใช้งานอย่างแข็งขันในโลกสมัยใหม่ และปริมาณการใช้ก็มีเพิ่มขึ้นทุกปี

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

เหตุใดคุณจึงต้องมีฐานข้อมูลอนุกรมเวลา เหตุใดคุณจึงใช้ฐานข้อมูลเชิงสัมพันธ์ปกติเพื่อจัดเก็บอนุกรมเวลาไม่ได้

เนื่องจากอนุกรมเวลามักจะมีข้อมูลจำนวนมาก ซึ่งยากต่อการจัดเก็บและประมวลผลในฐานข้อมูลทั่วไป ดังนั้นจึงมีฐานข้อมูลเฉพาะสำหรับอนุกรมเวลาปรากฏขึ้น ฐานเหล่านี้จัดเก็บคะแนนได้อย่างมีประสิทธิภาพ (timestamp, value) ด้วยกุญแจที่ให้มา โดยจัดเตรียม API สำหรับการอ่านข้อมูลที่เก็บไว้ตามคีย์ โดยคู่คีย์-ค่าเดียว หรือโดยคู่คีย์-ค่าหลายคู่ หรือตาม regexp ตัวอย่างเช่น คุณต้องการค้นหาโหลด CPU ของบริการทั้งหมดของคุณในศูนย์ข้อมูลในอเมริกา จากนั้นคุณจะต้องใช้การสืบค้นเทียมนี้

โดยทั่วไปแล้วฐานข้อมูลอนุกรมเวลาจะมีภาษาคิวรีแบบพิเศษ เนื่องจาก SQL อนุกรมเวลาไม่เหมาะนัก แม้ว่าจะมีฐานข้อมูลที่รองรับ SQL แต่ก็ไม่เหมาะสมมากนัก ภาษาแบบสอบถามเช่น PromQL, InfluxQL, การไหล, Q. ฉันหวังว่าจะมีคนได้ยินภาษาเหล่านี้อย่างน้อยหนึ่งภาษา หลายๆ คนคงเคยได้ยินเกี่ยวกับ PromQL มาก่อน นี่คือภาษาแบบสอบถามของ Prometheus

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

นี่คือลักษณะของสถาปัตยกรรมฐานข้อมูลอนุกรมเวลาสมัยใหม่โดยใช้ VictoriaMetrics เป็นตัวอย่าง

ประกอบด้วยสองส่วน นี่คือที่เก็บข้อมูลสำหรับดัชนีกลับหัวและที่เก็บข้อมูลสำหรับค่าอนุกรมเวลา ที่เก็บข้อมูลเหล่านี้ถูกแยกออกจากกัน

เมื่อมีบันทึกใหม่เข้ามาในฐานข้อมูล ก่อนอื่นเราจะเข้าถึงดัชนีแบบกลับด้านเพื่อค้นหาตัวระบุอนุกรมเวลาสำหรับชุดที่กำหนด label=value สำหรับเมตริกที่กำหนด เราค้นหาตัวระบุนี้และบันทึกค่าไว้ในที่เก็บข้อมูล

เมื่อมีคำขอดึงข้อมูลจาก TSDB เราจะไปที่ดัชนีแบบกลับหัวก่อน มารับทุกอย่างกันเถอะ timeseries_ids บันทึกที่ตรงกับชุดนี้ label=value. จากนั้นเราจะได้รับข้อมูลที่จำเป็นทั้งหมดจากคลังข้อมูลซึ่งจัดทำดัชนีโดย timeseries_ids.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ลองดูตัวอย่างวิธีที่ฐานข้อมูลอนุกรมเวลาประมวลผลแบบสอบถามแบบเลือกข้อมูลขาเข้า

  • ก่อนอื่นเธอได้รับทุกสิ่ง timeseries_ids จากดัชนีกลับหัวที่มีคู่ที่กำหนด label=valueหรือตอบสนองนิพจน์ทั่วไปที่กำหนด
  • จากนั้นจะดึงจุดข้อมูลทั้งหมดจากที่จัดเก็บข้อมูลในช่วงเวลาที่กำหนดสำหรับจุดที่พบ timeseries_ids.
  • หลังจากนี้ ฐานข้อมูลจะทำการคำนวณจุดข้อมูลเหล่านี้ตามคำขอของผู้ใช้ และหลังจากนั้นก็จะได้คำตอบกลับมา

ในการนำเสนอนี้ ผมจะเล่าให้คุณฟังเกี่ยวกับส่วนแรก นี่คือการค้นหา timeseries_ids โดยดัชนีกลับหัว คุณสามารถดูส่วนที่สองและส่วนที่สามได้ในภายหลัง แหล่งที่มาของ VictoriaMetricsหรือรอจนกว่าผมจะเตรียมรายงานอื่นๆ :)

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

มาดูดัชนีกลับกันดีกว่า หลายคนอาจคิดว่ามันเป็นเรื่องง่าย ใครจะรู้ว่าดัชนีกลับหัวคืออะไรและทำงานอย่างไร อ้าว คนไม่เยอะแล้ว ลองทำความเข้าใจว่ามันคืออะไร

จริงๆแล้วมันง่าย มันเป็นเพียงพจนานุกรมที่จับคู่คีย์กับค่า กุญแจคืออะไร? คู่นี้. label=valueที่ไหน label и value - นี่คือเส้น และค่าต่างๆจะเป็นชุด timeseries_idsซึ่งรวมถึงคู่ที่กำหนดด้วย label=value.

ดัชนีแบบกลับหัวช่วยให้คุณค้นหาทุกสิ่งได้อย่างรวดเร็ว timeseries_idsที่ได้ให้ label=value.

อีกทั้งยังช่วยให้คุณค้นหาได้อย่างรวดเร็ว timeseries_ids อนุกรมเวลาสำหรับหลายคู่ label=valueหรือสำหรับคู่รัก label=regexp. สิ่งนี้เกิดขึ้นได้อย่างไร? โดยการหาจุดตัดของเซต timeseries_ids สำหรับแต่ละคู่ label=value.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

มาดูการใช้งานต่างๆ ของดัชนีกลับหัวกัน เริ่มต้นด้วยการใช้งานที่ไร้เดียงสาที่ง่ายที่สุด เธอมีลักษณะเช่นนี้

ฟังก์ชัน getMetricIDs รับรายการสตริง แต่ละบรรทัดประกอบด้วย label=value. ฟังก์ชันนี้ส่งคืนรายการ metricIDs.

มันทำงานอย่างไร? ที่นี่เรามีตัวแปรโกลบอลที่เรียกว่า invertedIndex. นี่คือพจนานุกรมปกติ (map) ซึ่งจะแมปสตริงเพื่อแบ่ง ints ในบรรทัดประกอบด้วย label=value.

การใช้ฟังก์ชัน: get metricIDs สำหรับครั้งแรก label=valueแล้วเราจะผ่านเรื่องอื่นไป label=valueเราเข้าใจแล้ว metricIDs สำหรับพวกเขา. และเรียกใช้ฟังก์ชัน intersectIntsซึ่งจะกล่าวถึงด้านล่าง และฟังก์ชันนี้จะคืนค่าจุดตัดของรายการเหล่านี้

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

อย่างที่คุณเห็น การใช้ดัชนีกลับด้านนั้นไม่ซับซ้อนมากนัก แต่นี่เป็นการดำเนินการที่ไร้เดียงสา มันมีข้อเสียอะไรบ้าง? ข้อเสียเปรียบหลักของการใช้งานแบบไร้เดียงสาคือดัชนีกลับด้านดังกล่าวถูกเก็บไว้ใน RAM หลังจากรีสตาร์ทแอปพลิเคชันแล้ว เราจะสูญเสียดัชนีนี้ ไม่มีการบันทึกดัชนีนี้ลงดิสก์ ดัชนีกลับด้านดังกล่าวไม่น่าจะเหมาะกับฐานข้อมูล

ข้อเสียเปรียบประการที่สองเกี่ยวข้องกับหน่วยความจำด้วย ดัชนีกลับด้านจะต้องพอดีกับ RAM หากเกินขนาดของ RAM แสดงว่าเราจะเกิดข้อผิดพลาดหน่วยความจำไม่เพียงพออย่างแน่นอน และโปรแกรมจะไม่ทำงาน

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ปัญหานี้สามารถแก้ไขได้โดยใช้วิธีแก้ปัญหาสำเร็จรูปเช่น เลเวลดีบีหรือ ร็อกส์ดีบี.

กล่าวโดยสรุป เราต้องการฐานข้อมูลที่ช่วยให้เราสามารถดำเนินการสามอย่างได้อย่างรวดเร็ว

  • การดำเนินการครั้งแรกคือการบันทึก ключ-значение สู่ฐานข้อมูลนี้ เธอทำสิ่งนี้เร็วมากที่ไหน ключ-значение เป็นสตริงที่กำหนดเอง
  • การดำเนินการที่สองคือการค้นหาค่าอย่างรวดเร็วโดยใช้คีย์ที่กำหนด
  • และการดำเนินการที่สามคือการค้นหาค่าทั้งหมดอย่างรวดเร็วตามคำนำหน้าที่กำหนด

LevelDB และ RocksDB - ฐานข้อมูลเหล่านี้ได้รับการพัฒนาโดย Google และ Facebook อันดับแรกมาที่ LevelDB จากนั้นคนจาก Facebook ก็เอา LevelDB และเริ่มปรับปรุง พวกเขาสร้าง RocksDB ขณะนี้ฐานข้อมูลภายในเกือบทั้งหมดทำงานบน RocksDB ภายใน Facebook รวมถึงฐานข้อมูลที่ถ่ายโอนไปยัง RocksDB และ MySQL ด้วย พวกเขาตั้งชื่อเขา มายร็อคส์.

ดัชนีกลับหัวสามารถนำไปใช้ได้โดยใช้ LevelDB ทำอย่างไร? เราบันทึกเป็นกุญแจ label=value. และค่านี้คือตัวระบุอนุกรมเวลาที่มีคู่นี้อยู่ label=value.

หากเรามีอนุกรมเวลาหลายคู่กับคู่ที่กำหนด label=valueจากนั้นจะมีแถวหลายแถวในฐานข้อมูลนี้ซึ่งมีคีย์เดียวกันและต่างกัน timeseries_ids. เพื่อรับรายชื่อทั้งหมด timeseries_idsซึ่งเริ่มต้นด้วยสิ่งนี้ label=prefixเราจะทำการสแกนช่วงซึ่งฐานข้อมูลนี้ได้รับการปรับให้เหมาะสม นั่นคือเราเลือกบรรทัดทั้งหมดที่ขึ้นต้นด้วย label=prefix และได้รับสิ่งที่จำเป็น timeseries_ids.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

นี่คือตัวอย่างการใช้งานว่าจะมีลักษณะอย่างไรใน Go เรามีดัชนีกลับหัว นี่คือ LevelDB

ฟังก์ชันนี้เหมือนกับการใช้งานแบบไร้เดียงสา มันทำซ้ำการใช้งานที่ไร้เดียงสาเกือบจะทีละบรรทัด จุดเดียวคือแทนที่จะหันไป map เราเข้าถึงดัชนีกลับหัว เราได้รับค่าทั้งหมดเป็นอันดับแรก label=value. จากนั้นเราจะผ่านคู่ที่เหลือทั้งหมด label=value และรับชุดรหัสเมตริกที่เกี่ยวข้อง จากนั้นเราจะพบทางแยก

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ดูเหมือนทุกอย่างจะเรียบร้อยดี แต่มีข้อเสียในการแก้ปัญหานี้ VictoriaMetrics เริ่มใช้ดัชนีแบบกลับด้านโดยอิงตาม LevelDB แต่สุดท้ายฉันก็ต้องยอมแพ้

ทำไม เนื่องจาก LevelDB ช้ากว่าการใช้งานที่ไร้เดียงสา ในการใช้งานแบบไร้เดียงสา เมื่อได้รับคีย์ที่กำหนด เราจะดึงข้อมูลชิ้นส่วนทั้งหมดทันที metricIDs. นี่เป็นการดำเนินการที่รวดเร็วมาก - ชิ้นทั้งหมดพร้อมใช้งานแล้ว

ใน LevelDB ทุกครั้งที่มีการเรียกใช้ฟังก์ชัน GetValues คุณต้องผ่านทุกบรรทัดที่ขึ้นต้นด้วย label=value. และรับค่าของแต่ละบรรทัด timeseries_ids. ดังกล่าว timeseries_ids รวบรวมชิ้นส่วนเหล่านี้ timeseries_ids. แน่นอนว่าวิธีนี้ช้ากว่าการเข้าถึงแผนที่ปกติโดยใช้คีย์มาก

ข้อเสียเปรียบประการที่สองคือ LevelDB เขียนด้วยภาษา C การเรียกใช้ฟังก์ชัน C จาก Go นั้นไม่เร็วมาก ใช้เวลาหลายร้อยนาโนวินาที สิ่งนี้ไม่เร็วมากเพราะเมื่อเปรียบเทียบกับการเรียกใช้ฟังก์ชันปกติที่เขียนใน go ซึ่งใช้เวลา 1-5 นาโนวินาที ประสิทธิภาพที่แตกต่างกันเป็นสิบเท่า สำหรับ VictoriaMetrics นี่เป็นข้อบกพร่องร้ายแรง :)

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ดังนั้นฉันจึงเขียนการนำดัชนีกลับหัวไปใช้เอง และเขาก็โทรหาเธอ ผสาน.

Mergeset ขึ้นอยู่กับโครงสร้างข้อมูล MergeTree โครงสร้างข้อมูลนี้ยืมมาจาก ClickHouse แน่นอนว่า Mergeset ควรได้รับการปรับให้เหมาะสมเพื่อการค้นหาที่รวดเร็ว timeseries_ids ตามคีย์ที่กำหนด Mergeset เขียนในภาษา Go ทั้งหมด คุณสามารถดูได้ แหล่งที่มาของ VictoriaMetrics บน GitHub. การดำเนินการผสานอยู่ในโฟลเดอร์ /lib/mergeset. คุณสามารถลองคิดดูว่าเกิดอะไรขึ้นที่นั่น

Merset API คล้ายกับ LevelDB และ RocksDB มาก นั่นคือช่วยให้คุณสามารถบันทึกบันทึกใหม่ได้อย่างรวดเร็วและเลือกบันทึกตามคำนำหน้าที่กำหนดได้อย่างรวดเร็ว

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

เราจะพูดถึงข้อเสียของการผสานในภายหลัง ตอนนี้เรามาพูดถึงปัญหาที่เกิดขึ้นกับ VictoriaMetrics ในการผลิตเมื่อใช้ดัชนีแบบกลับด้าน

ทำไมพวกเขาถึงเกิดขึ้น?

เหตุผลแรกคืออัตราการปั่นสูง เมื่อแปลเป็นภาษารัสเซีย นี่เป็นการเปลี่ยนแปลงอนุกรมเวลาบ่อยครั้ง นี่คือเมื่ออนุกรมเวลาสิ้นสุดลงและมีอนุกรมเวลาใหม่เริ่มต้นขึ้น หรืออนุกรมเวลาใหม่หลายชุดเริ่มต้นขึ้น และสิ่งนี้เกิดขึ้นบ่อยครั้ง

เหตุผลที่สองคืออนุกรมเวลาจำนวนมาก ในช่วงแรกๆ เมื่อการมอนิเตอร์กำลังได้รับความนิยม จำนวนอนุกรมเวลาก็มีน้อย ตัวอย่างเช่น สำหรับคอมพิวเตอร์แต่ละเครื่อง คุณต้องตรวจสอบโหลด CPU, หน่วยความจำ, เครือข่าย และดิสก์ อนุกรมเวลา 4 ชุดต่อคอมพิวเตอร์หนึ่งเครื่อง สมมติว่าคุณมีคอมพิวเตอร์ 100 เครื่องและมีอนุกรมเวลา 400 เครื่อง นี่ก็น้อยมาก

เมื่อเวลาผ่านไป ผู้คนพบว่าพวกเขาสามารถวัดข้อมูลที่ละเอียดยิ่งขึ้นได้ ตัวอย่างเช่น ไม่ใช่วัดโหลดของโปรเซสเซอร์ทั้งหมด แต่แยกกันของคอร์โปรเซสเซอร์แต่ละตัว หากคุณมีคอร์โปรเซสเซอร์ 40 คอร์ คุณจะมีอนุกรมเวลาเพิ่มขึ้น 40 เท่าในการวัดโหลดของโปรเซสเซอร์

แต่นั่นไม่ใช่ทั้งหมด แกนประมวลผลแต่ละตัวสามารถมีได้หลายสถานะ เช่น ไม่ได้ใช้งาน เมื่อไม่ได้ใช้งาน และยังทำงานในพื้นที่ผู้ใช้ ทำงานในพื้นที่เคอร์เนล และสถานะอื่นๆ และแต่ละสถานะดังกล่าวยังสามารถวัดเป็นอนุกรมเวลาแยกกันได้ สิ่งนี้จะเพิ่มจำนวนแถวเพิ่มเติมอีก 7-8 เท่า

จากเมตริกหนึ่ง เราได้ 40 x 8 = 320 เมตริกสำหรับคอมพิวเตอร์เพียงเครื่องเดียว คูณด้วย 100 เราจะได้ 32 แทนที่จะเป็น 000.

จากนั้น Kubernetes ก็เข้ามา และมันแย่ลงไปอีกเพราะ Kubernetes สามารถโฮสต์บริการต่างๆ ได้มากมาย แต่ละบริการใน Kubernetes ประกอบด้วยพ็อดจำนวนมาก และทั้งหมดนี้จำเป็นต้องได้รับการตรวจสอบ นอกจากนี้เรายังมีการปรับใช้บริการเวอร์ชันใหม่ๆ ของคุณอย่างต่อเนื่อง สำหรับเวอร์ชันใหม่แต่ละเวอร์ชัน จะต้องสร้างอนุกรมเวลาใหม่ เป็นผลให้จำนวนอนุกรมเวลาเพิ่มขึ้นแบบทวีคูณ และเรากำลังเผชิญกับปัญหาอนุกรมเวลาจำนวนมาก ซึ่งเรียกว่าภาวะคาร์ดินัลลิตีสูง VictoriaMetrics รับมือกับมันได้สำเร็จเมื่อเปรียบเทียบกับฐานข้อมูลอนุกรมเวลาอื่นๆ

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

มาดูอัตราการปั่นป่วนที่สูงกันดีกว่า อะไรทำให้อัตราการปั่นในการผลิตสูง? เนื่องจากความหมายบางอย่างของป้ายกำกับและแท็กมีการเปลี่ยนแปลงอยู่ตลอดเวลา

ตัวอย่างเช่น ยกตัวอย่าง Kubernetes ซึ่งมีแนวคิด deploymentเช่น เมื่อมีการเปิดตัวแอปพลิเคชันเวอร์ชันใหม่ของคุณ ด้วยเหตุผลบางประการ นักพัฒนา Kubernetes จึงตัดสินใจเพิ่มรหัสการปรับใช้ลงในป้ายกำกับ

สิ่งนี้นำไปสู่อะไร? ยิ่งไปกว่านั้น เมื่อมีการปรับใช้ใหม่แต่ละครั้ง อนุกรมเวลาเก่าทั้งหมดจะถูกขัดจังหวะ และแทนที่จะเป็นอนุกรมเวลาใหม่จะเริ่มต้นด้วยค่าป้ายกำกับใหม่ deployment_id. อาจมีแถวดังกล่าวหลายแสนหรือหลายล้านแถว

สิ่งสำคัญเกี่ยวกับเรื่องทั้งหมดนี้คือจำนวนอนุกรมเวลาทั้งหมดเพิ่มขึ้น แต่จำนวนอนุกรมเวลาที่ใช้งานอยู่และรับข้อมูลยังคงที่ สถานะนี้เรียกว่าอัตราการปั่นป่วนสูง

ปัญหาหลักของอัตราการปั่นป่วนที่สูงคือเพื่อให้แน่ใจว่าความเร็วในการค้นหาคงที่สำหรับอนุกรมเวลาทั้งหมดสำหรับชุดป้ายกำกับที่กำหนดในช่วงเวลาที่กำหนด โดยทั่วไปนี่คือช่วงเวลาของชั่วโมงสุดท้ายหรือวันสุดท้าย

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

จะแก้ไขปัญหานี้อย่างไร? นี่คือตัวเลือกแรก นี่คือการแบ่งดัชนีกลับหัวออกเป็นส่วนๆ เมื่อเวลาผ่านไป นั่นคือบางช่วงเวลาผ่านไป เราจะเสร็จสิ้นการทำงานกับดัชนีกลับหัวปัจจุบัน และสร้างดัชนีกลับหัวใหม่ ช่วงเวลาหนึ่งผ่านไป เราก็สร้างช่วงเวลาใหม่ขึ้นมาอีก

และเมื่อสุ่มตัวอย่างจากดัชนีกลับหัวเหล่านี้ เราจะพบชุดของดัชนีกลับหัวที่อยู่ภายในช่วงเวลาที่กำหนด และด้วยเหตุนี้ เราจึงเลือกรหัสอนุกรมเวลาจากที่นั่น

ซึ่งช่วยประหยัดทรัพยากรเพราะเราไม่ต้องดูชิ้นส่วนที่ไม่อยู่ในระยะเวลาที่กำหนด โดยปกติแล้ว ถ้าเราเลือกข้อมูลสำหรับชั่วโมงสุดท้าย จากนั้นสำหรับช่วงเวลาก่อนหน้า เราจะข้ามคำขอ

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

มีตัวเลือกอื่นในการแก้ปัญหานี้ นี่คือการจัดเก็บรายการรหัสอนุกรมเวลาแยกต่างหากในแต่ละวันที่เกิดขึ้นในวันนั้น

ข้อดีของโซลูชันนี้เหนือโซลูชันก่อนหน้านี้คือ เราไม่ทำซ้ำข้อมูลอนุกรมเวลาที่ไม่หายไปเมื่อเวลาผ่านไป มีอยู่ตลอดเวลาและไม่เปลี่ยนแปลง

ข้อเสียคือโซลูชันดังกล่าวใช้งานยากกว่าและแก้ไขจุดบกพร่องได้ยากกว่า และ VictoriaMetrics ก็เลือกโซลูชันนี้ นี่คือสิ่งที่เกิดขึ้นในอดีต โซลูชันนี้ยังทำงานได้ดีเมื่อเทียบกับโซลูชันก่อนหน้า เนื่องจากโซลูชันนี้ไม่ได้ถูกนำมาใช้เนื่องจากจำเป็นต้องทำซ้ำข้อมูลในแต่ละพาร์ติชันสำหรับอนุกรมเวลาที่ไม่เปลี่ยนแปลง กล่าวคือ ที่ไม่หายไปเมื่อเวลาผ่านไป VictoriaMetrics ได้รับการปรับให้เหมาะสมสำหรับการใช้พื้นที่ดิสก์เป็นหลัก และการใช้งานก่อนหน้านี้ทำให้การใช้พื้นที่ดิสก์แย่ลง แต่การใช้งานนี้เหมาะกว่าในการลดการใช้พื้นที่ดิสก์จึงถูกเลือก

ฉันต้องต่อสู้กับเธอ ปัญหาคือในการนำไปใช้นี้ คุณยังต้องเลือกจำนวนที่มากกว่ามาก timeseries_ids สำหรับข้อมูลมากกว่าเมื่อดัชนีกลับด้านถูกแบ่งพาร์ติชันเวลา

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

เราแก้ไขปัญหานี้ได้อย่างไร? เราแก้ไขมันด้วยวิธีดั้งเดิม - โดยการจัดเก็บตัวระบุอนุกรมเวลาหลายรายการไว้ในแต่ละรายการดัชนีแบบกลับหัว แทนที่จะเป็นตัวระบุตัวเดียว นั่นคือเรามีกุญแจ label=valueซึ่งเกิดขึ้นในทุกอนุกรมเวลา และตอนนี้เราประหยัดได้หลายอย่าง timeseries_ids ในรายการเดียว

นี่คือตัวอย่าง ก่อนหน้านี้เรามี N รายการ แต่ตอนนี้เรามีหนึ่งรายการที่มีคำนำหน้าเหมือนกันกับรายการอื่นทั้งหมด สำหรับรายการก่อนหน้า ค่าจะมีรหัสอนุกรมเวลาทั้งหมด

ทำให้สามารถเพิ่มความเร็วในการสแกนของดัชนีกลับด้านดังกล่าวได้สูงสุดถึง 10 เท่า และช่วยให้เราลดการใช้หน่วยความจำสำหรับแคชได้ เนื่องจากตอนนี้เราจัดเก็บสตริงแล้ว label=value เพียงครั้งเดียวในแคชด้วยกัน N ครั้ง และบรรทัดนี้อาจมีขนาดใหญ่หากคุณเก็บบรรทัดยาวๆ ไว้ในแท็กและป้ายกำกับของคุณ ซึ่ง Kubernetes ชอบยัดไว้ตรงนั้น

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

อีกทางเลือกหนึ่งในการเร่งการค้นหาดัชนีแบบกลับด้านก็คือการแบ่งส่วน การสร้างดัชนีกลับหัวหลายดัชนีแทนที่จะเป็นดัชนีเดียวและแบ่งข้อมูลระหว่างดัชนีเหล่านั้นด้วยคีย์ นี่คือชุด key=value ไอน้ำ. นั่นคือเราได้รับดัชนีกลับหัวอิสระหลายตัวซึ่งเราสามารถสืบค้นพร้อมกันบนโปรเซสเซอร์หลายตัว การใช้งานก่อนหน้านี้อนุญาตให้ดำเนินการในโหมดโปรเซสเซอร์ตัวเดียวเท่านั้น เช่น การสแกนข้อมูลบนคอร์เดียวเท่านั้น โซลูชันนี้ช่วยให้คุณสามารถสแกนข้อมูลบนหลายคอร์พร้อมกันได้ ดังที่ ClickHouse ชอบทำ นี่คือสิ่งที่เราวางแผนที่จะดำเนินการ

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ทีนี้กลับมาที่แกะของเรา - ไปที่ฟังก์ชันทางแยก timeseries_ids. ลองพิจารณาว่าอาจมีการใช้งานอะไรบ้าง ฟังก์ชั่นนี้ช่วยให้คุณค้นหา timeseries_ids สำหรับชุดที่กำหนด label=value.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ตัวเลือกแรกคือการใช้งานที่ไร้เดียงสา สองลูปซ้อนกัน ที่นี่เราได้รับอินพุตฟังก์ชัน intersectInts สองชิ้น - a и b. ที่เอาต์พุต มันควรกลับมาหาเราที่จุดตัดของส่วนเหล่านี้

การใช้งานที่ไร้เดียงสามีลักษณะเช่นนี้ เราวนซ้ำค่าทั้งหมดจากสไลซ์ aภายในวงนี้เราจะผ่านค่าทั้งหมดของสไลซ์ b. และเราเปรียบเทียบพวกเขา หากตรงกันแสดงว่าเราพบทางแยกแล้ว และบันทึกไว้ใน result.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ข้อเสียคืออะไร? ความซับซ้อนกำลังสองเป็นข้อเสียเปรียบหลัก ตัวอย่างเช่น หากมิติข้อมูลของคุณเป็นแบบแบ่งส่วน a и b ครั้งละหนึ่งล้านฟังก์ชันนี้จะไม่ส่งคืนคำตอบให้กับคุณ เพราะมันจะต้องทำซ้ำหนึ่งล้านล้านครั้ง ซึ่งถือว่ามากแม้แต่กับคอมพิวเตอร์สมัยใหม่ก็ตาม

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

การใช้งานครั้งที่สองจะขึ้นอยู่กับแผนที่ เราสร้างแผนที่ เราใส่ค่าทั้งหมดจากสไลซ์ลงในแผนที่นี้ a. จากนั้นเราก็ผ่านการตัดเป็นวงแยกกัน b. และเราตรวจสอบว่าค่านี้มาจากสไลซ์หรือไม่ b ในแผนที่ หากมีอยู่แล้วให้เพิ่มเข้าไปในผลลัพธ์

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

มีประโยชน์อะไรบ้าง? ข้อดีคือมีความซับซ้อนเชิงเส้นเท่านั้น นั่นคือฟังก์ชันจะทำงานเร็วขึ้นมากสำหรับชิ้นที่ใหญ่กว่า สำหรับสไลซ์ขนาดล้านชิ้น ฟังก์ชันนี้จะดำเนินการซ้ำ 2 ล้านครั้ง เทียบกับฟังก์ชันก่อนหน้าที่ทำซ้ำหลายล้านล้านครั้ง

ข้อเสียคือฟังก์ชันนี้ต้องใช้หน่วยความจำเพิ่มเติมเพื่อสร้างแผนที่นี้

ข้อเสียเปรียบประการที่สองคือค่าใช้จ่ายจำนวนมากสำหรับการแฮช ข้อเสียเปรียบนี้ไม่ชัดเจนมาก และสำหรับเรา มันก็ไม่ได้ชัดเจนนักเช่นกัน ดังนั้นในตอนแรก VictoriaMetrics การนำสี่แยกไปใช้นั้นทำผ่านแผนที่ แต่จากนั้น การทำโปรไฟล์แสดงให้เห็นว่าเวลาของโปรเซสเซอร์หลักถูกใช้ไปกับการเขียนลงบนแผนที่และตรวจสอบการมีอยู่ของค่าในแผนที่นี้

เหตุใดเวลา CPU จึงสูญเปล่าในสถานที่เหล่านี้ เนื่องจาก Go ดำเนินการแฮชบนบรรทัดเหล่านี้ นั่นคือจะคำนวณแฮชของคีย์เพื่อเข้าถึงที่ดัชนีที่กำหนดใน HashMap การดำเนินการคำนวณแฮชจะเสร็จสิ้นภายในสิบนาโนวินาที สิ่งนี้ช้าสำหรับ VictoriaMetrics

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ฉันตัดสินใจใช้บิตเซ็ตที่ปรับให้เหมาะสมสำหรับกรณีนี้โดยเฉพาะ นี่คือลักษณะของจุดตัดของสองชิ้นในตอนนี้ ที่นี่เราสร้างบิตเซ็ต เราเพิ่มองค์ประกอบจากชิ้นแรกลงไป จากนั้นเราจะตรวจสอบการมีอยู่ขององค์ประกอบเหล่านี้ในส่วนที่สอง และเพิ่มเข้าไปในผลลัพธ์ นั่นคือแทบไม่ต่างจากตัวอย่างที่แล้ว สิ่งเดียวที่นี่คือเราแทนที่การเข้าถึงแผนที่ด้วยฟังก์ชันที่กำหนดเอง add и has.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

เมื่อมองแวบแรก ดูเหมือนว่าสิ่งนี้ควรจะทำงานช้าลง หากก่อนหน้านี้มีการใช้แผนที่มาตรฐานที่นั่น จากนั้นจึงเรียกใช้ฟังก์ชันอื่นๆ แต่การทำโปรไฟล์แสดงให้เห็นว่าสิ่งนี้ทำงานได้เร็วกว่าแผนที่มาตรฐาน 10 เท่าในกรณีของ VictoriaMetrics

นอกจากนี้ยังใช้หน่วยความจำน้อยกว่ามากเมื่อเทียบกับการใช้งานแผนที่ เนื่องจากเราจัดเก็บบิตไว้ที่นี่แทนที่จะเป็นค่าแปดไบต์

ข้อเสียของการดำเนินการนี้คือไม่ชัดเจนนักและไม่สำคัญ

ข้อเสียเปรียบอีกประการหนึ่งที่หลายคนอาจไม่สังเกตเห็นก็คือ การใช้งานนี้อาจทำงานได้ไม่ดีในบางกรณี นั่นคือ ได้รับการปรับให้เหมาะสมสำหรับกรณีเฉพาะ สำหรับกรณีนี้ที่จุดตัดของรหัสอนุกรมเวลา VictoriaMetrics ไม่ได้หมายความว่าจะเหมาะสำหรับทุกกรณี หากใช้ไม่ถูกต้อง เราจะไม่ได้รับการเพิ่มประสิทธิภาพ แต่เป็นข้อผิดพลาดหน่วยความจำไม่เพียงพอและประสิทธิภาพการทำงานช้าลง

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

พิจารณาการนำโครงสร้างนี้ไปใช้ หากคุณต้องการดู ข้อมูลนั้นจะอยู่ในแหล่งที่มาของ VictoriaMetrics ในโฟลเดอร์ lib/uint64set. ได้รับการปรับให้เหมาะสมที่สุดสำหรับกรณี VictoriaMetrics โดยเฉพาะ โดยที่ timeseries_id เป็นค่า 64 บิต โดยที่ 32 บิตแรกโดยทั่วไปจะคงที่และเปลี่ยนเฉพาะ 32 บิตสุดท้ายเท่านั้น

โครงสร้างข้อมูลนี้ไม่ได้จัดเก็บไว้ในดิสก์ แต่จะทำงานในหน่วยความจำเท่านั้น

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

นี่คือ API ของมัน มันไม่ซับซ้อนมาก API ได้รับการปรับแต่งให้เหมาะกับตัวอย่างเฉพาะของการใช้ VictoriaMetrics โดยเฉพาะ นั่นคือไม่มีฟังก์ชั่นที่ไม่จำเป็นที่นี่ ต่อไปนี้เป็นฟังก์ชันที่ VictoriaMetrics ใช้อย่างชัดเจน

มีฟังก์ชั่น addซึ่งเพิ่มค่าใหม่ มีฟังก์ชั่น hasซึ่งจะตรวจสอบค่าใหม่ และมีฟังก์ชั่น delซึ่งจะลบค่า มีฟังก์ชั่นช่วยเหลือ lenซึ่งส่งคืนขนาดของชุด การทำงาน clone โคลนนิ่งมาก และฟังก์ชั่น appendto แปลงชุดนี้เป็นชิ้น timeseries_ids.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

นี่คือลักษณะการใช้งานโครงสร้างข้อมูลนี้ set มีสององค์ประกอบ:

  • ItemsCount เป็นช่องตัวช่วยเพื่อส่งคืนจำนวนองค์ประกอบในชุดได้อย่างรวดเร็ว อาจเป็นไปได้หากไม่มีฟิลด์เสริมนี้ แต่ต้องเพิ่มที่นี่เนื่องจาก VictoriaMetrics มักจะสืบค้นความยาวบิตเซ็ตในอัลกอริทึม

  • สนามที่สองคือ buckets. นี่คือชิ้นส่วนจากโครงสร้าง bucket32. แต่ละโครงสร้างร้านค้า hi สนาม. เหล่านี้คือ 32 บิตบน และสองชิ้น - b16his и buckets ของ bucket16 โครงสร้าง

16 บิตบนสุดของส่วนที่สองของโครงสร้าง 64 บิตจะถูกเก็บไว้ที่นี่ และที่นี่บิตเซ็ตจะถูกเก็บไว้สำหรับ 16 บิตล่างของแต่ละไบต์

Bucket64 ประกอบด้วยอาร์เรย์ uint64. ความยาวคำนวณโดยใช้ค่าคงที่เหล่านี้ ในหนึ่งเดียว bucket16 สามารถจัดเก็บได้สูงสุด 2^16=65536 นิดหน่อย. ถ้าคุณหารสิ่งนี้ด้วย 8 ก็จะได้ 8 กิโลไบต์ ถ้าคุณหารด้วย 8 อีกครั้ง มันคือ 1000 uint64 ความหมาย. นั่นคือ Bucket16 – นี่คือโครงสร้าง 8 กิโลไบต์ของเรา

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

มาดูกันว่าวิธีใดวิธีหนึ่งของโครงสร้างนี้ในการเพิ่มค่าใหม่ถูกนำไปใช้อย่างไร

ทุกอย่างเริ่มต้นด้วย uint64 ความหมาย เราคำนวณ 32 บิตบน เราคำนวณ 32 บิตล่าง ผ่านไปทุกอย่างกันเถอะ buckets. เราเปรียบเทียบ 32 บิตบนสุดในแต่ละบัคเก็ตกับมูลค่าที่กำลังเพิ่ม และถ้ามันตรงกัน เราก็จะเรียกใช้ฟังก์ชันนี้ add ในโครงสร้าง b32 buckets. และเพิ่ม 32 บิตล่างลงไปตรงนั้น แล้วถ้ามันกลับมา. trueนั่นหมายความว่าเราได้บวกค่าดังกล่าวลงไปแต่เราไม่มีค่าดังกล่าว ถ้ามันกลับมา falseความหมายเช่นนั้นก็มีอยู่แล้ว จากนั้นเราจะเพิ่มจำนวนองค์ประกอบในโครงสร้าง

ถ้าเราไม่พบสิ่งที่คุณต้องการ bucket ด้วยค่าสูงที่ต้องการ จากนั้นเราจะเรียกใช้ฟังก์ชัน addAllocซึ่งจะผลิตอันใหม่ขึ้นมา bucketโดยเพิ่มเข้าไปในโครงสร้างที่เก็บข้อมูล

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

นี่คือการนำฟังก์ชันไปใช้ b32.add. มันคล้ายกับการดำเนินการครั้งก่อน เราคำนวณ 16 บิตที่สำคัญที่สุด 16 บิตที่มีนัยสำคัญน้อยที่สุด

จากนั้นเราจะผ่าน 16 บิตบนทั้งหมด เราพบการแข่งขัน และหากมีคู่กันเราจะเรียกวิธีเพิ่มซึ่งเราจะพิจารณาในหน้าถัดไป bucket16.

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

และนี่คือระดับต่ำสุดที่ควรปรับปรุงให้มากที่สุด เราคำนวณหา uint64 ค่า id เป็นชิ้นบิตและด้วย bitmask. นี่คือมาสก์สำหรับค่า 64 บิตที่กำหนด ซึ่งสามารถใช้เพื่อตรวจสอบการมีอยู่ของบิตนี้หรือตั้งค่าได้ เราตรวจสอบว่าบิตนี้ถูกตั้งค่าและตั้งค่าแล้วส่งคืนสถานะ นี่คือการดำเนินการของเรา ซึ่งช่วยให้เราสามารถเร่งความเร็วการดำเนินการตัดกันรหัสของอนุกรมเวลาได้ 10 เท่าเมื่อเทียบกับแผนที่ทั่วไป

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

นอกเหนือจากการเพิ่มประสิทธิภาพนี้ VictoriaMetrics ยังมีการเพิ่มประสิทธิภาพอื่นๆ อีกมากมาย การเพิ่มประสิทธิภาพเหล่านี้ส่วนใหญ่ถูกเพิ่มเข้ามาด้วยเหตุผล แต่หลังจากโปรไฟล์โค้ดในการผลิตแล้ว

นี่คือกฎหลักของการปรับให้เหมาะสม อย่าเพิ่มการปรับให้เหมาะสมโดยสมมติว่าจะมีปัญหาคอขวดที่นี่ เพราะอาจกลายเป็นว่าไม่มีปัญหาคอขวดที่นั่น การเพิ่มประสิทธิภาพมักจะลดคุณภาพของโค้ด ดังนั้นจึงคุ้มค่าที่จะปรับให้เหมาะสมเฉพาะหลังจากการทำโปรไฟล์และโดยเฉพาะอย่างยิ่งในการผลิตเพื่อให้นี่คือข้อมูลจริง หากใครสนใจ คุณสามารถดูซอร์สโค้ด VictoriaMetrics และสำรวจการเพิ่มประสิทธิภาพอื่นๆ ที่มีอยู่ได้

ไปเพิ่มประสิทธิภาพใน VictoriaMetrics อเล็กซานเดอร์ วัลยาลคิน

ฉันมีคำถามเกี่ยวกับบิตเซ็ต คล้ายกันมากกับการใช้งานบูลเวกเตอร์ C ++ บิตเซ็ตที่ปรับให้เหมาะสม คุณได้ดำเนินการจากที่นั่นหรือไม่?

ไม่ ไม่ใช่จากที่นั่น เมื่อใช้บิตเซ็ตนี้ ฉันได้รับคำแนะนำจากความรู้เกี่ยวกับโครงสร้างของอนุกรมเวลาของ ID เหล่านี้ ซึ่งใช้ใน VictoriaMetrics และโครงสร้างของมันเป็นเช่นนั้น โดยพื้นฐานแล้ว 32 บิตบนนั้นคงที่ 32 บิตล่างอาจมีการเปลี่ยนแปลง ยิ่งบิตต่ำเท่าไรก็ยิ่งสามารถเปลี่ยนแปลงได้บ่อยขึ้นเท่านั้น ดังนั้นการใช้งานนี้จึงได้รับการปรับให้เหมาะสมที่สุดสำหรับโครงสร้างข้อมูลนี้โดยเฉพาะ เท่าที่ฉันรู้ การใช้งาน C++ ได้รับการปรับให้เหมาะสมสำหรับกรณีทั่วไป หากคุณปรับให้เหมาะสมสำหรับกรณีทั่วไป หมายความว่าจะไม่เหมาะสมที่สุดสำหรับกรณีเฉพาะ

ฉันแนะนำให้คุณดูรายงานของ Alexey Milovid ด้วย ประมาณหนึ่งเดือนที่แล้ว เขาได้พูดคุยเกี่ยวกับการเพิ่มประสิทธิภาพใน ClickHouse สำหรับความเชี่ยวชาญเฉพาะด้าน เขาเพียงบอกว่าในกรณีทั่วไป การใช้งาน C++ หรือการใช้งานอื่นๆ บางอย่างได้รับการปรับแต่งให้ทำงานได้ดีโดยเฉลี่ยในโรงพยาบาล อาจทำงานได้แย่กว่าการใช้งานเฉพาะความรู้เช่นเรา โดยที่เรารู้ว่า 32 บิตบนสุดส่วนใหญ่จะคงที่

ฉันมีคำถามที่สอง อะไรคือความแตกต่างพื้นฐานจาก InfluxDB?

มีความแตกต่างพื้นฐานหลายประการ ในแง่ของประสิทธิภาพและการใช้หน่วยความจำ InfluxDB ในการทดสอบจะแสดงการใช้หน่วยความจำเพิ่มขึ้น 10 เท่าสำหรับอนุกรมเวลาที่มีคาร์ดินัลลิตี้สูง เมื่อคุณมีจำนวนมาก เช่น ล้าน เป็นต้น ตัวอย่างเช่น VictoriaMetrics ใช้ 1 GB ต่อล้านแถวที่ใช้งานอยู่ ในขณะที่ InfluxDB ใช้ 10 GB และนั่นคือความแตกต่างใหญ่

ความแตกต่างพื้นฐานประการที่สองคือ InfluxDB มีภาษาคิวรีแปลก ๆ - Flux และ InfluxQL ไม่สะดวกในการทำงานกับอนุกรมเวลามากนัก PromQLซึ่งได้รับการสนับสนุนโดย VictoriaMetrics PromQL เป็นภาษาคิวรีจาก Prometheus

และข้อแตกต่างอีกอย่างหนึ่งก็คือ InfluxDB มีโมเดลข้อมูลที่แปลกเล็กน้อย โดยแต่ละบรรทัดสามารถจัดเก็บหลายฟิลด์ด้วยชุดแท็กที่แตกต่างกัน เส้นเหล่านี้ยังแบ่งออกเป็นตารางต่างๆ เพิ่มเติม ภาวะแทรกซ้อนเพิ่มเติมเหล่านี้ทำให้การทำงานในภายหลังกับฐานข้อมูลนี้ซับซ้อนขึ้น เป็นการยากที่จะสนับสนุนและเข้าใจ

ใน VictoriaMetrics ทุกอย่างง่ายกว่ามาก โดยแต่ละอนุกรมเวลาจะเป็นคีย์-ค่า ค่าคือชุดของคะแนน - (timestamp, value)และที่สำคัญคือชุด label=value. ไม่มีการแบ่งแยกระหว่างเขตข้อมูลและการวัด ช่วยให้คุณสามารถเลือกข้อมูลใดๆ แล้วรวม บวก ลบ คูณ หาร ซึ่งแตกต่างจาก InfluxDB ที่การคำนวณระหว่างแถวต่างๆ ยังคงไม่ถูกนำมาใช้เท่าที่ฉันรู้ ถึงแม้จะนำไปใช้จริงก็ยากแต่ต้องเขียนโค้ดเยอะมาก

ฉันมีคำถามชี้แจง ฉันเข้าใจถูกต้องหรือไม่ว่ามีปัญหาบางอย่างที่คุณพูดถึง ดัชนีกลับด้านนี้ไม่พอดีกับหน่วยความจำ ดังนั้นจึงมีการแบ่งพาร์ติชันที่นั่น

อันดับแรก ฉันแสดงให้เห็นการใช้งานดัชนีกลับหัวอย่างไร้เดียงสาบนแผนที่ Go มาตรฐาน การใช้งานนี้ไม่เหมาะสำหรับฐานข้อมูลเนื่องจากดัชนีกลับด้านนี้ไม่ได้ถูกบันทึกลงดิสก์ และฐานข้อมูลต้องบันทึกลงดิสก์เพื่อให้ข้อมูลนี้ยังคงพร้อมใช้งานเมื่อเริ่มระบบใหม่ ในการใช้งานนี้ เมื่อคุณรีสตาร์ทแอปพลิเคชัน ดัชนีกลับด้านของคุณจะหายไป และคุณจะไม่สามารถเข้าถึงข้อมูลทั้งหมดได้เนื่องจากคุณจะไม่สามารถค้นหาข้อมูลได้

สวัสดี! ขอบคุณสำหรับรายงาน! ฉันชื่อพาเวล ฉันมาจากไวลด์เบอร์รี่ ฉันมีคำถามสองสามข้อสำหรับคุณ คำถามที่หนึ่ง คุณคิดว่าหากคุณเลือกหลักการอื่นเมื่อสร้างสถาปัตยกรรมของแอปพลิเคชันของคุณและแบ่งพาร์ติชันข้อมูลเมื่อเวลาผ่านไป บางทีคุณอาจสามารถตัดข้อมูลเมื่อทำการค้นหา โดยขึ้นอยู่กับข้อเท็จจริงที่ว่าพาร์ติชันหนึ่งมีข้อมูลสำหรับหนึ่งพาร์ติชัน ช่วงเวลาหนึ่ง นั่นคือในช่วงเวลาหนึ่งและคุณไม่ต้องกังวลว่าชิ้นส่วนของคุณจะกระจัดกระจายแตกต่างกันออกไปใช่ไหม คำถามข้อที่ 2 - เนื่องจากคุณกำลังใช้อัลกอริธึมที่คล้ายกันกับบิตเซ็ตและอย่างอื่น บางทีคุณอาจลองใช้คำสั่งของโปรเซสเซอร์ บางทีคุณอาจลองใช้การเพิ่มประสิทธิภาพดังกล่าวแล้ว?

ฉันจะตอบข้อที่สองทันที เรายังไปไม่ถึงจุดนั้น แต่ถ้าจำเป็นเราก็จะไปถึงที่นั่น และคำถามแรกคืออะไร?

คุณได้กล่าวถึงสองสถานการณ์ และพวกเขาบอกว่าพวกเขาเลือกอันที่สองที่มีการใช้งานที่ซับซ้อนกว่า และพวกเขาไม่ชอบอันแรกซึ่งมีการแบ่งพาร์ติชันข้อมูลตามเวลา

ใช่. ในกรณีแรก ปริมาณรวมของดัชนีจะมีมากขึ้น เนื่องจากในแต่ละพาร์ติชัน เราจะต้องจัดเก็บข้อมูลที่ซ้ำกันสำหรับอนุกรมเวลาเหล่านั้นที่ดำเนินต่อไปในพาร์ติชันเหล่านี้ทั้งหมด และหากอัตราการปั่นอนุกรมเวลาของคุณน้อย เช่น มีการใช้อนุกรมเดียวกันอย่างต่อเนื่อง ในกรณีแรก เราจะสูญเสียพื้นที่ดิสก์ที่ถูกครอบครองมากขึ้นเมื่อเทียบกับกรณีที่สอง

ใช่แล้ว การแบ่งเวลาเป็นทางเลือกที่ดี โพรมีธีอุสใช้มัน แต่โพรมีธีอุสมีข้อเสียเปรียบอีกประการหนึ่ง เมื่อรวมข้อมูลเหล่านี้ จะต้องเก็บข้อมูลเมตาในหน่วยความจำสำหรับป้ายกำกับและอนุกรมเวลาทั้งหมด ดังนั้น หากชิ้นส่วนข้อมูลที่ผสานมีขนาดใหญ่ การใช้หน่วยความจำจะเพิ่มขึ้นอย่างมากในระหว่างการรวม ซึ่งแตกต่างจาก VictoriaMetrics เมื่อทำการรวม VictoriaMetrics จะไม่ใช้หน่วยความจำเลย โดยจะใช้เพียง XNUMX-XNUMX กิโลไบต์เท่านั้น โดยไม่คำนึงถึงขนาดของข้อมูลที่รวมเข้าด้วยกัน

อัลกอริทึมที่คุณใช้ใช้หน่วยความจำ โดยจะทำเครื่องหมายแท็กอนุกรมเวลาที่มีค่า และด้วยวิธีนี้ คุณจะตรวจสอบการมีอยู่ที่จับคู่กันในอาร์เรย์ข้อมูลหนึ่งและอีกอาร์เรย์หนึ่ง และคุณเข้าใจว่าจุดตัดเกิดขึ้นหรือไม่ โดยทั่วไปแล้ว ฐานข้อมูลจะใช้เคอร์เซอร์และตัววนซ้ำที่จัดเก็บเนื้อหาปัจจุบันและเรียกใช้ผ่านข้อมูลที่เรียงลำดับเนื่องจากความซับซ้อนทั่วไปของการดำเนินการเหล่านี้

ทำไมเราไม่ใช้เคอร์เซอร์เพื่อสำรวจข้อมูล?

ใช่

เราจัดเก็บแถวที่เรียงลำดับไว้ใน LevelDB หรือชุดผสาน เราสามารถเลื่อนเคอร์เซอร์และค้นหาจุดตัดได้ ทำไมเราไม่ใช้มัน? เพราะมันช้า.. เนื่องจากเคอร์เซอร์หมายความว่าคุณต้องเรียกใช้ฟังก์ชันสำหรับแต่ละบรรทัด การเรียกใช้ฟังก์ชันคือ 5 นาโนวินาที และถ้าคุณมี 100 บรรทัด ปรากฎว่าเราใช้เวลาครึ่งวินาทีในการเรียกใช้ฟังก์ชันนี้

มีสิ่งนั้นใช่ และคำถามสุดท้ายของฉัน คำถามอาจฟังดูแปลกไปสักหน่อย เหตุใดจึงไม่สามารถอ่านการรวมที่จำเป็นทั้งหมดในขณะที่ข้อมูลมาถึงและบันทึกไว้ในรูปแบบที่ต้องการได้ เหตุใดจึงต้องประหยัดปริมาณมหาศาลในบางระบบ เช่น VictoriaMetrics, ClickHouse ฯลฯ แล้วใช้เวลากับมันมาก

ฉันจะยกตัวอย่างเพื่อให้ชัดเจนยิ่งขึ้น สมมติว่ามาตรวัดความเร็วของเล่นขนาดเล็กทำงานอย่างไร โดยจะบันทึกระยะทางที่คุณเดินทาง โดยบวกเป็นค่าเดียวและครั้งที่สองตลอดเวลา และแบ่ง และได้รับความเร็วเฉลี่ย คุณสามารถทำสิ่งเดียวกันได้ เพิ่มข้อเท็จจริงที่จำเป็นทั้งหมดได้ทันที

โอเค ฉันเข้าใจคำถามแล้ว ตัวอย่างของคุณมีที่ของมัน หากคุณรู้ว่าคุณต้องการการรวมแบบใด นี่คือการใช้งานที่ดีที่สุด แต่ปัญหาคือผู้คนบันทึกตัวชี้วัดเหล่านี้ ข้อมูลบางส่วนใน ClickHouse และยังไม่รู้ว่าจะรวบรวมและกรองอย่างไรในอนาคต ดังนั้นพวกเขาจึงต้องบันทึกข้อมูลดิบทั้งหมด แต่ถ้าคุณรู้ว่าคุณต้องคำนวณบางอย่างโดยเฉลี่ย ทำไมไม่ลองคำนวณแทนการเก็บค่าดิบจำนวนมากไว้ตรงนั้นล่ะ แต่นี่เป็นเพียงเมื่อคุณรู้แน่ชัดว่าคุณต้องการอะไร

อย่างไรก็ตาม ฐานข้อมูลสำหรับจัดเก็บอนุกรมเวลารองรับการนับผลรวม ตัวอย่างเช่น Prometheus รองรับ กฎการบันทึก. นั่นคือสามารถทำได้หากคุณรู้ว่าคุณต้องการหน่วยใด VictoriaMetrics ยังไม่มีสิ่งนี้ แต่โดยปกติแล้วจะมี Prometheus นำหน้า ซึ่งสามารถทำได้ในกฎการเข้ารหัส

ตัวอย่างเช่น ในงานก่อนหน้าของฉัน ฉันต้องนับจำนวนเหตุการณ์ในหน้าต่างแบบเลื่อนในชั่วโมงที่ผ่านมา ปัญหาคือฉันต้องดำเนินการแบบกำหนดเองใน Go นั่นคือบริการสำหรับการนับสิ่งนี้ บริการนี้ไม่สำคัญในท้ายที่สุด เนื่องจากเป็นการยากที่จะคำนวณ การใช้งานสามารถทำได้ง่าย หากคุณต้องการนับผลรวมบางส่วนในช่วงเวลาที่กำหนด หากคุณต้องการนับเหตุการณ์ในหน้าต่างบานเลื่อน มันไม่ง่ายอย่างที่คิด ฉันคิดว่าสิ่งนี้ยังไม่ได้ถูกนำมาใช้ใน ClickHouse หรือในฐานข้อมูลอนุกรมเวลา เนื่องจากเป็นการยากที่จะนำไปใช้

และอีกหนึ่งคำถาม เราแค่พูดถึงการหาค่าเฉลี่ย และฉันจำได้ว่าครั้งหนึ่งเคยมีเรื่องแบบนี้ เช่น กราไฟท์ที่มีแบ็กเอนด์คาร์บอน และเขารู้วิธีที่จะแบ่งข้อมูลเก่าออก เช่น เหลือหนึ่งจุดต่อนาที หนึ่งจุดต่อชั่วโมง ฯลฯ โดยหลักการแล้ว สิ่งนี้ค่อนข้างสะดวกหากเราต้องการข้อมูลดิบ พูดง่ายๆ เป็นเวลาหนึ่งเดือน และอย่างอื่นสามารถทำได้ ผอมลง แต่ Prometheus และ VictoriaMetrics ไม่รองรับฟังก์ชันนี้ มีการวางแผนรองรับหรือไม่? ถ้าไม่ทำไมจะไม่ได้?

ขอบคุณสำหรับคำถาม ผู้ใช้ของเราถามคำถามนี้เป็นระยะ พวกเขาถามว่าเราจะเพิ่มการสนับสนุนสำหรับการสุ่มตัวอย่างเมื่อใด มีปัญหาหลายประการที่นี่ ประการแรกผู้ใช้ทุกคนเข้าใจ downsampling บางสิ่งที่แตกต่าง: บางคนต้องการได้รับจุดใดก็ได้ในช่วงเวลาที่กำหนด บางคนต้องการค่าสูงสุด ต่ำสุด ค่าเฉลี่ย หากหลายระบบเขียนข้อมูลลงในฐานข้อมูลของคุณ คุณจะไม่สามารถรวมข้อมูลทั้งหมดเข้าด้วยกันได้ อาจเป็นไปได้ว่าแต่ละระบบต้องการการทำให้ผอมบางที่แตกต่างกัน และนี่เป็นเรื่องยากที่จะปฏิบัติ

และอย่างที่สองก็คือ VictoriaMetrics เช่น ClickHouse ได้รับการปรับให้เหมาะสมสำหรับการทำงานกับข้อมูลดิบจำนวนมาก ดังนั้นจึงสามารถขุดบรรทัดนับพันล้านบรรทัดได้ในเวลาไม่ถึงวินาทีหากคุณมีคอร์จำนวนมากในระบบของคุณ การสแกนอนุกรมเวลาใน VictoriaMetrics – 50 จุดต่อวินาทีต่อคอร์ และประสิทธิภาพนี้จะปรับขนาดตามคอร์ที่มีอยู่ นั่นคือ หากคุณมี 000 คอร์ คุณจะสแกนหนึ่งพันล้านจุดต่อวินาที และคุณสมบัติของ VictoriaMetrics และ ClickHouse นี้ช่วยลดความจำเป็นในการลดขนาดลง

คุณสมบัติอีกอย่างหนึ่งคือ VictoriaMetrics บีบอัดข้อมูลนี้อย่างมีประสิทธิภาพ การบีบอัดโดยเฉลี่ยในการผลิตคือตั้งแต่ 0,4 ถึง 0,8 ไบต์ต่อจุด แต่ละจุดคือการประทับเวลา + ค่า และถูกบีบอัดโดยเฉลี่ยน้อยกว่าหนึ่งไบต์

เซอร์เกย์. ฉันมีคำถาม. ควอนตัมเวลาในการบันทึกขั้นต่ำคือเท่าใด

หนึ่งมิลลิวินาที เมื่อเร็วๆ นี้เราได้พูดคุยกับนักพัฒนาฐานข้อมูลอนุกรมเวลาอื่นๆ ส่วนแบ่งเวลาขั้นต่ำคือหนึ่งวินาที และในกราไฟท์ก็เท่ากับหนึ่งวินาทีเช่นกัน ใน OpenTSDB จะใช้เวลาหนึ่งวินาทีเช่นกัน InfluxDB มีความแม่นยำระดับนาโนวินาที ใน VictoriaMetrics จะใช้เวลาหนึ่งมิลลิวินาที เนื่องจากใน Prometheus จะใช้เวลาหนึ่งมิลลิวินาที และ VictoriaMetrics เดิมทีได้รับการพัฒนาให้เป็นที่จัดเก็บข้อมูลระยะไกลสำหรับ Prometheus แต่ตอนนี้สามารถบันทึกข้อมูลจากระบบอื่นได้แล้ว

คนที่ฉันได้พูดคุยด้วยบอกว่าพวกเขามีความแม่นยำแบบวินาทีต่อวินาที นั่นก็เพียงพอแล้วสำหรับพวกเขา เพราะมันขึ้นอยู่กับประเภทของข้อมูลที่จัดเก็บไว้ในฐานข้อมูลอนุกรมเวลา หากนี่คือข้อมูล DevOps หรือข้อมูลจากโครงสร้างพื้นฐานที่คุณรวบรวมไว้ในช่วงเวลา 30 วินาทีต่อนาที ความแม่นยำระดับที่สองก็เพียงพอแล้ว คุณไม่จำเป็นต้องมีอะไรน้อยไปกว่านี้ และหากคุณรวบรวมข้อมูลนี้จากระบบการซื้อขายที่มีความถี่สูง คุณจะต้องมีความแม่นยำระดับนาโนวินาที

ความแม่นยำระดับมิลลิวินาทีใน VictoriaMetrics ยังเหมาะสำหรับกรณี DevOps อีกด้วย และเหมาะสำหรับกรณีส่วนใหญ่ที่ผมกล่าวถึงตอนต้นของรายงาน สิ่งเดียวที่อาจไม่เหมาะคือระบบการซื้อขายที่มีความถี่สูง

ขอบคุณ! และอีกคำถามหนึ่ง ความเข้ากันได้ใน PromQL คืออะไร

ความเข้ากันได้แบบย้อนหลังเต็มรูปแบบ VictoriaMetrics รองรับ PromQL อย่างสมบูรณ์ นอกจากนี้ยังเพิ่มฟังก์ชันขั้นสูงเพิ่มเติมใน PromQL ซึ่งเรียกว่า เมตริก QL. มีการพูดคุยบน YouTube เกี่ยวกับฟังก์ชันเพิ่มเติมนี้ ฉันได้พูดที่งาน Monitoring Meetup ในฤดูใบไม้ผลิที่เซนต์ปีเตอร์สเบิร์ก

ช่องโทรเลข วิคตอเรียเมตริกส์.

เฉพาะผู้ใช้ที่ลงทะเบียนเท่านั้นที่สามารถเข้าร่วมในการสำรวจได้ เข้าสู่ระบบ, โปรด.

อะไรขัดขวางไม่ให้คุณเปลี่ยนมาใช้ VictoriaMetrics เพื่อเป็นการจัดเก็บข้อมูลระยะยาวสำหรับ Prometheus (เขียนในความคิดเห็นฉันจะเพิ่มลงในแบบสำรวจ))

  • ลด 71,4%ฉันไม่ได้ใช้ Prometheus5

  • ลด 28,6%ไม่รู้เกี่ยวกับ VictoriaMetrics2

ผู้ใช้ 7 คนโหวต ผู้ใช้ 12 รายงดออกเสียง

ที่มา: will.com

เพิ่มความคิดเห็น