Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> ฐานข้อมูล

ความคิดเกี่ยวกับประสิทธิภาพของ Redis

ความคิดเกี่ยวกับประสิทธิภาพของ Redis

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

เมตริกประสิทธิภาพ – คือ Latency King หรือไม่

มีสองตัวชี้วัดประสิทธิภาพที่คุณกังวลเป็นหลักเมื่อใช้ Redis:ฉันสามารถดำเนินการคำสั่ง (หรือธุรกรรม) ได้กี่คำสั่งต่อวินาที และใช้เวลานานแค่ไหน เมื่อคุณทำลายมันลง คุณพบว่าอดีตเป็นผลรองจากอย่างหลัง เนื่องจาก Redis เป็นแบบเธรดเดียว จำนวน ops/วินาที ที่คุณสามารถกดได้นั้นสัมพันธ์กับระยะเวลาที่ใช้ ดังนั้น สิ่งที่สำคัญที่สุดคือสิ่งที่ฉันเรียกว่า "เวลาในการตอบสนองของคำสั่ง"

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

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

เวลาในการตอบสนองของคำสั่ง

แน่นอนว่า Redis ก็เช่นกัน อย่างไรก็ตาม ความแตกต่างที่นี่คือการรักษาตรรกะการกรอง การเรียงลำดับ และทุกสิ่งที่คุณไม่สามารถดำเนินการในคำสั่ง Redis เดียวหรืออย่างน้อยสองสามคำสั่ง คุณจะไม่โหลด DB ลงด้วยตรรกะ – และดังนั้น "สิ่งที่ต้องดำเนินการ" . ควรใช้ Redis เป็น "ที่เก็บข้อมูล" ไม่ใช่ "เซิร์ฟเวอร์ฐานข้อมูล" แบบเดิม นี่เป็นแง่มุมแรกของ "อย่าทำให้ Redis ช้าลง" ที่คุณต้องทำ ไม่จำเป็นต้องระบุว่าเมื่อคุณเริ่มต้นเส้นทางของ Lua scripting คุณจะเสี่ยงต่อประสิทธิภาพสุทธิที่ต่ำลง คุณอาจไม่เห็นการพัฒนาเมื่อการเข้าชมของคุณต่ำถึงปานกลาง อย่างไรก็ตาม เมื่อคุณตีเกล็ดขนาดใหญ่ คุณจะเห็นมัน และเมื่อถึงตอนนั้น ตรรกะก็มักจะถูกหลอมรวมเข้าไปแล้ว และกลายเป็นหนี้ทางเทคนิคจำนวนมหาศาลที่จะย้ายเข้าสู่รหัสแอปพลิเคชัน เราทุกคนทราบดีว่าการเคลียร์หนี้ทางเทคนิคมีความสำคัญมากเพียงใด

นี่ไม่ได้หมายความว่าสคริปต์ Lua ไม่มีสถานที่ มันแค่หมายความว่าควรได้รับการพิจารณาอย่างถี่ถ้วน กฎข้อที่ดีเมื่อสคริปต์ Lua เป็นหรือไม่สูญเสียประสิทธิภาพสุทธิคือการเปรียบเทียบต้นทุนของการเดินทางไปกลับเพิ่มเติมที่คุณต้องดำเนินการหากคุณจัดการกับฝั่งไคลเอ็นต์ตรรกะนั้น อย่างไรก็ตาม ไม่ใช่ว่ารหัสลูกค้าของคุณจะทำได้นานแค่ไหน พิจารณาดังนี้:หากคุณลดค่าใช้จ่ายในการเดินทางไปกลับ 2 มิลลิวินาที แต่เพิ่ม 3 มิลลิวินาทีในการดำเนินการสคริปต์ แสดงว่าคุณไปผิดทาง

ที่นี่เราจำเป็นต้องตระหนักดีถึงลักษณะของเซิร์ฟเวอร์แบบเธรดเดียว สคริปต์ 3ms นั้นกำลังบล็อกคำสั่งที่เป็นไปได้หลายร้อย (หรือหลายพัน) ขณะดำเนินการ หากคุณแยกสิ่งเหล่านั้นออกเป็นลำดับ (ดึง) -> (ตรรกะ) -> (ดึง) เซิร์ฟเวอร์สามารถประมวลผลคำขอเพิ่มเติมในระหว่างขั้นตอน “(ตรรกะ)” การรักษาตรรกะในรหัสไคลเอ็นต์จะช่วยให้คุณสามารถรักษาภาวะพร้อมกันของระบบที่ใช้หลายไคลเอ็นต์ได้ หากคุณต้องการธุรกรรมหรือสคริปต์ Lua ให้ใช้แน่นอน แต่อย่าใช้เพราะจะทำให้โค้ดของคุณ "ง่ายขึ้น" พึงระวังประสิทธิภาพการทำงานพร้อมกันที่กระทบ วัดผล และตัดสินใจเลือกอย่างมีสติ

สิ่งนี้นำเราไปสู่กฎข้อที่สองของ “อย่าทำให้ Redis Down ช้าลง”:รักษาการทำงานพร้อมกันโดยหลีกเลี่ยงตรรกะของเซิร์ฟเวอร์ผ่านสคริปต์ ประโยชน์ด้านข้างคือความสามารถในการโยกย้ายไปยังการตั้งค่า Redis Cluster โดยไม่ต้องเขียนใหม่หรือทิ้งสคริปต์ Lua ซึ่งทำงานบนหลายคีย์

วิธีอื่นที่ทำให้ Redis ช้าลงได้

มีการเรียกใช้เซิร์ฟเวอร์ Redis ในระดับระบบหรือการทำงานบางประการ ซึ่งอาจทำให้ Redis ทำงานช้าลง เช่นเดียวกับเซิร์ฟเวอร์ใดๆ ที่ใช้ขีดจำกัดทรัพยากร I/O อาจทำให้ Redis ช้าลงได้ ตัวอย่างเช่น หากคุณต้องการแบนด์วิดท์เครือข่าย 8GB แต่มี 1GB มันจะ "ช้า" สำหรับคุณ หากกระบวนการ daemon ของคุณถูกจำกัดให้เปิดซ็อกเก็ตน้อยกว่าที่คุณต้องการ การเชื่อมต่อพร้อมกันจะถูกใช้ไปเพื่อรอการปิดการเชื่อมต่อแทนที่จะดำเนินการคำสั่ง

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

ข้อแรกได้รับการกล่าวถึงค่อนข้างดีในวรรณกรรม Redis มาตรฐาน:อย่าวางไว้บน Xen hypervisor VM อย่างที่สอง ความเพียร ดูเหมือนจะมี แต่ยังไม่ถึงเกณฑ์ในการประมาณของฉัน

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

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

แฝงความคงอยู่

สิ่งนี้นำเราไปสู่หลักการแรกของสิ่งที่ฉันเรียกว่า "เวลาแฝงที่คงอยู่" – เวลาตั้งแต่คำสั่งที่กระทบกับเซิร์ฟเวอร์ไปจนถึงผลลัพธ์ที่กระทบต่อรูปแบบการคงอยู่บางรูปแบบ:ค้นหาเวลาแฝงที่น้อยที่สุดที่แนะนำตัวเลือกการคงอยู่ที่คุณทำได้ ขึ้นอยู่กับเครือข่ายและดิสก์ของคุณ เซิร์ฟเวอร์ AoF หรือ Slave จะเป็นตัวเลือกการคงอยู่ของการชนที่มีเวลาแฝงต่ำที่สุด โดย RDB จะมาเป็นอันดับสุดท้าย

RDB จะมาในลำดับสุดท้าย เนื่องจากมีความล่าช้าในตัวของการเปลี่ยนแปลง N ในช่วงเวลา T วินาที ดังนั้น สมมติว่าคุณมีการเปลี่ยนแปลงเพียงพอในระยะเวลาที่น้อยที่สุดนั้น (หน้าต่างเริ่มต้นที่เล็กที่สุดคือ 60 วินาที) การหน่วงเวลาการคงอยู่ของคุณคือช่วงเวลา T + เวลาในการเขียน RDB ไปยังดิสก์ หากใช้เวลา 30 วินาทีในการดัมพ์หน่วยความจำนั้นไปยังดิสก์โดยมีช่วงเวลาเริ่มต้น 60 วินาทีตามค่าเริ่มต้น “เวลาแฝงที่คงอยู่” ของคุณจะเป็น (60+30) 90 วินาที

อย่างไรก็ตาม สิ่งนี้ทำให้เกิดคำถามว่าเวลาแฝงของการคงอยู่นี้เป็นปัญหาหรือไม่ คำถามนี้มีสองด้าน:1) เพียงพอสำหรับความต้องการทางธุรกิจของคุณหรือไม่? และ 2) ทำให้ Redis ของคุณช้าลงหรือไม่

คำถามแรกคือคำถามที่ฉันไม่สามารถให้คำตอบทั่วไปที่ตอบทุกคนได้ อย่างไรก็ตาม ฉันสามารถพูดได้ว่าหากความต้องการของคุณสำหรับเวลาแฝงของการคงอยู่นั้นเข้มงวดกว่าที่สูตรข้างต้นเปิดเผย คุณจะได้รับคำตอบมีแนวโน้มที่จะ "ใช้ทาสและ/หรือ AoF" แทน RDB นี่ถือว่าคุณไม่ได้ทำผิดพลาดอย่างเห็นได้ชัดบนแพลตฟอร์มที่คุณใช้ Redis ซึ่งนำเราไปสู่แง่มุมที่สอง:ทำให้ Redis ช้าลงหรือไม่

สำหรับคำถามบางข้อที่ว่า "ต้องใช้เวลานานเท่าใดในการบันทึกไฟล์ RDB" กลายเป็นสิ่งสำคัญที่สุดในความคิดของพวกเขา ในความคิดของฉัน นี่เป็นความผิดพลาด มันสำคัญว่าต้องใช้เวลานานแค่ไหน? คำตอบสำหรับคำถามนี้คือ "การบันทึกทำให้ Redis ช้าลงหรือไม่" ถ้าไม่เช่นนั้น คุณไม่ควรสนใจว่าจะใช้เวลา 1 วินาทีหรือ 1 ชั่วโมง ตัวอย่างเช่น พิจารณาเซิร์ฟเวอร์ A ซึ่งใช้เวลา 1,000 วินาทีในการบันทึก RDB ในขณะที่ไม่ได้บันทึกช่วงแฝงของคำสั่งที่แท้จริงคือ 30-100 ไมโครวินาที ในระหว่างการบันทึกเวลาแฝงนี้ยังอยู่ในช่วง 30-100 ไมโครวินาที ในกรณีนี้ จะเป็นการปรับให้เหมาะสมก่อนเวลาอันควรในการทำงานเพื่อลด RDB นี้ ประหยัดเวลาภายใต้แนวคิดว่าคุณมีประสิทธิภาพ Redis ต่ำ

อย่างไรก็ตาม เซิร์ฟเวอร์ B ใช้เวลาเพียง 10 วินาที แต่เวลาแฝงของคำสั่งเพิ่มขึ้นจาก 30-100us เป็น 130-250us ตอนนี้คุณมีเหตุผลที่ต้องกังวลว่าไฟล์ RDB จะใช้เวลานานแค่ไหนในการสร้าง เนื่องจากการบันทึกทำให้ Redis ทำงานช้าลง และคุณต้องการย่อให้เล็กสุด หากนั่นหมายถึงดิสก์ที่เร็วขึ้น อย่างน้อยตอนนี้คุณก็มีเหตุผลที่จะปรับมัน สมมติว่าการเพิ่มขึ้นประมาณ 100-150 ไมโครวินาทีทำให้เกิดความวิตกกังวลด้านประสิทธิภาพสำหรับแอปพลิเคชันของคุณ หากไม่เป็นเช่นนั้น แสดงว่าคุณกลับไปสู่การเพิ่มประสิทธิภาพก่อนกำหนด

เกี่ยวกับวิธีวัดเวลาแฝงนั้น ฉันจะลงรายละเอียดเพิ่มเติมในส่วนที่สองของโพสต์นี้ เนื่องจากบทความนี้ค่อนข้างยาวแล้ว