วิธีที่ดีที่สุดในการใช้คิวตามตารางพร้อมกัน


11

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

ฉันจะมั่นใจได้อย่างไรว่าแต่ละระเบียนจะถูกเลือกโดยแอปเดียวเท่านั้น มีวิธีการตั้งค่าสถานะ / ล็อกระเบียนหรือไม่

ตอนนี้เพื่อหลีกเลี่ยงการรับลิงค์เดียวกันสองครั้งขึ้นไปฉันอนุญาตให้แต่ละอินสแตนซ์รับเฉพาะชุดระเบียน (ตาม MOD ของ ID) แต่นี่ไม่ใช่วิธีที่โปร่งใสในการเพิ่มการประมวลผลคิว เพิ่มความเร็วเพียงแค่เพิ่มอินสแตนซ์ใหม่


มนต์ของฉัน: "อย่าเข้าคิวเพียงแค่ทำมัน" นั่นคือแทนที่จะโยนภารกิจลงในคิวเรียกใช้กระบวนการเพื่อทำงาน
Rick James เมื่อ

คำตอบ:


8

ข้อแรก: MySQL เป็นหนึ่งในซอฟต์แวร์ที่แย่ที่สุดที่จะนำมาใช้ในการดำเนินการนี้โดยเฉพาะอย่างยิ่งถ้ามันเป็นแบบไดนามิกมาก เหตุผลก็คือเอ็นจิ้นเช่น MEMORY และ MyISAM มีเพียงระบบล็อคเต็มตารางในขณะที่เอ็นจิ้นที่เหมาะสมกว่าเช่น InnoDB มีโทษการเขียนสูงกว่า (เพื่อให้มีคุณสมบัติของกรด) และได้รับการปรับให้เหมาะสมสำหรับการเข้าถึงระเบียน ) นอกจากนี้ยังไม่มีระบบการแจ้งเตือนการเปลี่ยนแปลงที่ดีสำหรับ MySQL - จะต้องมีการใช้งานเป็นโพล มีซอฟต์แวร์หลายสิบชิ้นที่ปรับให้เหมาะกับงานนั้นมากขึ้น

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

SELECT FOR UPDATEคือสิ่งที่คุณกำลังมองหา - อ่านเป็นอันดับ ในขณะที่ UPDATE / DELETE จะล็อคแถวระหว่างการทำธุรกรรม MYSQL ที่กำลังทำงานอยู่เสมอคุณอาจต้องการหลีกเลี่ยงการทำธุรกรรมขนาดใหญ่ในขณะที่กระบวนการกำลังดำเนินการอยู่ดังนั้น:

START TRANSACTION;
SELECT * FROM your_table WHERE state != 'PROCESSING' 
  ORDER BY date_added ASC LIMIT 1 FOR UPDATE;
if (rows_selected = 0) { //finished processing the queue, abort}
else {
UPDATE your_table WHERE id = $row.id SET state = 'PROCESSING'
COMMIT;

// row is processed here, outside of the transaction, and it can take as much time as we want

// once we finish:
DELETE FROM your_table WHERE id = $row.id and state = 'PROCESSING' LIMIT 1;
}

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


ขอบคุณ คุณคิดว่าประสิทธิภาพจะได้ประโยชน์จากการล็อคที่มากขึ้นหรือไม่ (โดยการเปลี่ยน LIMIT เป็น 10)
Miguel E

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

1
และอาจเป็นความคิดที่ดีที่จะติดตามวันที่ที่คุณเริ่มประมวลผลแถวในกรณีที่กระบวนการหยุดทำงานและคุณต้องการใช้กลไกการหมดเวลา
Julian

3

ดังที่ฉันได้อธิบายไว้ในบทความนี้ MySQL 8 ได้แนะนำการสนับสนุนทั้งการล็อคข้ามและไม่ต้องรอ

SKIP LOCKED มีประโยชน์สำหรับการใช้คิวงาน (aka แบทช์คิว) เพื่อให้คุณสามารถข้ามการล็อคที่ล็อคไว้แล้วโดยธุรกรรมอื่นพร้อมกัน

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

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


0

ฉันได้ทำสิ่งที่คล้ายกับการตรวจสอบ DBCC ออฟไลน์ (เซิร์ฟเวอร์สองเครื่องที่ทำการสำรองข้อมูลคืนค่าและจากนั้นตรวจสอบ DBCC) เซิร์ฟเวอร์หนึ่งรวบรวมข้อมูลสำรองทั้งหมด 31 เซิร์ฟเวอร์เมื่อวานนี้และวางลงในคิวจากนั้นเซิร์ฟเวอร์นั้นและอีกเซิร์ฟเวอร์จะดึงข้อมูลจากคิวนั้น ในขณะที่เซิร์ฟเวอร์ไม่มากวิธีควรยังคงเหมือนเดิม: ให้แอปพลิเคชันเซิร์ฟเวอร์เรียกใช้คิวรีการอัปเดตกับคิวที่อัปเดตฟิลด์วันที่ / เวลาและฟิลด์ "เซิร์ฟเวอร์แอป" ด้วยชื่อของเซิร์ฟเวอร์แอปนั้น นี่จะทำให้การล็อกหรือหากมีการล็อคจากเซิร์ฟเวอร์อื่นที่ได้รับแถวถัดไปแล้วมันจะถูกบล็อกและรอให้แอปอื่น ๆ สิ้นสุดการรับแถวถัดไป จากนั้นคุณจะต้องการให้แอปดึงระเบียนล่าสุดจากคิวสำหรับฟิลด์แอปและรับข้อมูลใด ๆ ที่คุณต้องการ ใช้ MySQL '

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.