วิธีการตรวจสอบ master ใน mysql master-slave


17

ฉันกำลังตั้งค่าการจำลองแบบ MySQL Master-slave และฉันกำลังพยายามหาวิธีจัดการกับสถานการณ์ที่ล้มเหลวซึ่งฉันเลื่อนตำแหน่งสลาฟไปเป็นมาสเตอร์ (ในกรณีที่มาสเตอร์ลงไป)

แอ็พพลิเคชันเซิร์ฟเวอร์ของฉันต้องกำหนดให้การเขียนทั้งหมดไปยังต้นแบบปัจจุบัน แต่ฉันไม่สามารถใช้ HA ระดับเซิร์ฟเวอร์ระหว่างต้นแบบและทาส (heartbeat, keepalived) เนื่องจากเซิร์ฟเวอร์ db สองตัวอยู่บนเครือข่ายย่อยที่แตกต่างกันโดยสิ้นเชิงในตำแหน่งที่ตั้งทางกายภาพที่แตกต่างกัน

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

มีแบบสอบถามใน MySQL เพื่อดูว่าเซิร์ฟเวอร์ปัจจุบันเป็นหลักในแบบจำลองต้นแบบทาสหรือไม่?


คุณใช้ MySQL เวอร์ชันใด ???
RolandoMySQLDBA

นี่คือการส่งออก mysqlServer version: 5.5.23 MySQL Community Server (GPL)
อีธาน Hayon

คำตอบ:


13

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

และนั่นคือคำแถลงที่แท้จริง :)

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

ฉันสามารถค้นหาเซิร์ฟเวอร์ทั้งสองและถามว่าเซิร์ฟเวอร์ใดเป็นเซิร์ฟเวอร์หลักแล้วดำเนินการสอบถามทั้งหมดไปยังเซิร์ฟเวอร์นั้น

ปัญหาคือว่าในการจำลองแบบ MySQL ต้นแบบไม่เคยรู้จริง ๆ ว่ามันเป็นต้นแบบ

แนวคิดของ "promotion to master" ไม่ใช่แนวคิดในการจำลองแบบอะซิงโครนัสของ MySQL "การโปรโมต" เซิร์ฟเวอร์ MySQL ไปที่บทบาทหลักคือสิ่งที่เกิดขึ้น "ภายนอก" เซิร์ฟเวอร์ MySQL ซึ่งตรงข้ามกับสิ่งที่เกิดขึ้น "ภายใน" กับเซิร์ฟเวอร์ MySQL

"การส่งเสริมการขายเป็นหลัก" ไม่ได้ดำเนินการโดยการจัดเตรียมเซิร์ฟเวอร์ใด ๆ เพราะในทางเทคนิคแล้วเซิร์ฟเวอร์ MySQL ทุกเครื่องที่เปิดใช้งานการบันทึกแบบไบนารีนั้นเป็นผู้เชี่ยวชาญแม้ว่าจะไม่เคยมีทาสก็ตาม SHOW MASTER STATUSทำงานในลักษณะเดียวกันและส่งกลับผลลัพธ์เดียวกันทาสหรือไม่และต้นแบบที่มี 2 ทาสไม่ได้เป็นเจ้านายมากกว่าทาสที่มีทาส 1 คนหรือทาส 0 คน ในทำนองเดียวกันเจ้านายที่มีทาสทุกคนออฟไลน์ยังคงเป็นเจ้านายอยู่มากเพราะเมื่อทาสกลับมาออนไลน์พวกเขาจะรับการจำลองที่พวกเขาทิ้งไว้

เรียกได้ว่า "การรับรู้" เพียงอย่างเดียวในส่วนของเซิร์ฟเวอร์นั้นไม่ว่าจะเป็นมาสเตอร์ แต่จะเป็นทาส (หรือ "ไม่ใช่")

นั่นคือสิ่งที่ทางออกของ Rolando ถาม: "คุณเป็นทาสหรือไม่" หากคำตอบคือไม่แล้วสมมติฐานก็คือว่านี้จะต้องเป็นเจ้านาย ... ซึ่งเขาก็ชี้ให้เห็นว่าเป็นข้อสันนิษฐานข้อบกพร่องหากSTOP SLAVE;มีการออก แต่ทาสที่ถูกหยุดยังคงเป็นทาสดังนั้น "ไม่ใช่ทาส" (ในเวลาใดก็ได้) ไม่ถือเอาว่าเป็น "เจ้านาย"

การทดสอบที่คล้ายกันสามารถทำได้กับผู้เชี่ยวชาญสันนิษฐานว่า:

SELECT COUNT(1) FROM information_schema.processlist
 WHERE user = 'the_username_used_by_the_slave';

หรือ

SELECT COUNT(1) FROM information_schema.processlist
 WHERE command = 'binlog dump';

หากค่าเป็นศูนย์แสดงว่า IO thread ของ slave ไม่ได้เชื่อมต่อ การทดสอบนี้มีข้อบกพร่องที่คล้ายกันซึ่งหากทาสถูกตัดการเชื่อมต่อการบริหารแยกหรือล้มเหลวแล้วมันจะไม่ถูกเชื่อมต่อ ดังนั้นนี่ไม่ได้แก้อะไรด้วย

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

โซลูชันที่มีน้ำหนักเบากว่านี้คือ:

SELECT @@global.read_only;

บนทาสคุณสามารถ / ควรตั้งค่าตัวแปรส่วนกลางread_onlyเพื่อให้ผู้ใช้ที่ไม่มีSUPERสิทธิ์ไม่สามารถเขียนลงไปโดยไม่ได้ตั้งใจ (และแอปพลิเคชันของคุณไม่ควรมีSUPER) หากคุณ "เลื่อนขั้น" ทาสด้วยตนเองไปยังบทบาทหลักคุณSET GLOBAL read_only = OFFต้องเปิดใช้งานการเขียน (การจำลองแบบสามารถเขียนถึงทาสได้เสมอไม่ว่าจะตั้งค่าอย่างไร)

แต่นี่ฉันคิดว่ายังคงพลาดจุดสำคัญ:

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

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

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

สมมติว่าคุณพบข้อผิดพลาดและเกิดข้อผิดพลาดจากซอฟต์แวร์ mysqld_safeรีสตาร์ทตามหน้าที่mysqldและการกู้คืนความเสียหายของ InnoDB ดำเนินการอย่างไม่มีที่ติ แต่นั่นใช้เวลาไม่กี่นาที

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

ตอนนี้ต้นแบบดั้งเดิมกลับมาออนไลน์อีกครั้ง

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

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

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

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

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

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

คุณไม่สามารถปรับใช้เครื่องมือ HA บนเซิร์ฟเวอร์ MySQL ได้เนื่องจากมีการแยกออกจากกัน แต่คุณสามารถนำไปใช้กับ HAProxy ที่ทำงานบนแอพพลิเคชันเซิร์ฟเวอร์ แอปพลิเคชันเชื่อมต่อกับ "MySQL" บนโลคัลโฮสต์ซึ่งไม่ใช่ MySQL เลย แต่จริงๆแล้ว HAProxy ... และจะส่งต่อการเชื่อมต่อ TCP ไปยังเครื่อง MySQL ที่เหมาะสม

HAProxy สามารถทดสอบการเชื่อมต่อไปยังเซิร์ฟเวอร์ MySQL และเสนอการรับส่งข้อมูลไปยังเครื่อง MySQL ที่ยอมรับการเชื่อมต่อและอนุญาตการพิสูจน์ตัวตนเท่านั้น

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

หรือสำหรับการตั้งค่าด้วยตนเองอย่างเข้มงวดไปกับสิ่งที่ง่ายกว่า "การค้นพบ" เช่นรายการใน/etc/hostsไฟล์เซิร์ฟเวอร์แอปที่มีชื่อโฮสต์ที่แอปพลิเคชันใช้เชื่อมต่อกับ MySQL ซึ่งคุณสามารถอัปเดตด้วยตนเองได้ ต้นแบบมีวัตถุประสงค์เพื่อเป็นกระบวนการแบบแมนนวล

หรือสิ่งที่ซับซ้อนยิ่งขึ้นโดยใช้ Percona XtraDB Cluster อย่างไรก็ตามคุณต้องการเพิ่มเซิร์ฟเวอร์ตัวที่สามเนื่องจากมี 3 โหนดใน PXC หาก 2 เซิร์ฟเวอร์สามารถเห็นกันและกัน แต่แยกจากเซิร์ฟเวอร์ 1 ตัว (ถ้าทั้งสามยังคงทำงานอยู่) เซิร์ฟเวอร์ทั้งสองทำงานอย่างมีความสุข แต่ เซิร์ฟเวอร์ 1 ขดตัวเป็นลูกบอลเล็ก ๆ และปฏิเสธที่จะทำอะไรเพราะมันรู้ว่ามันจะต้องเป็นคนแปลก วิธีนี้ใช้งานได้เนื่องจาก 2 รู้ว่าพวกเขายังคงเป็นโหนดส่วนใหญ่ที่ออนไลน์ก่อนที่เครือข่ายจะแยกและ 1 ก็ตระหนักว่ามันไม่ใช่ ด้วย PXC มันไม่สำคัญว่าเซิร์ฟเวอร์ของคุณจะเชื่อมต่อกับแอปพลิเคชันของคุณ

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


ก่อนอื่นขอขอบคุณสำหรับการตอบรับที่ดี ฉันคิดว่าคุณเสนอทางออกที่ดี ฉันเคยคิดเกี่ยวกับการใช้การจำลองแบบวงกลมในอดีต แต่ได้อ่านสิ่งเลวร้ายเกี่ยวกับความน่าเชื่อถือ อย่างไรก็ตามปัญหาเหล่านี้ส่วนใหญ่สามารถป้องกันได้โดยการแก้ไข auto_increment_increment, auto_increment_offset ฯลฯ ... การใช้ HAProxy แบบโลคอลบนเซิร์ฟเวอร์แอปพลิเคชั่น ตรรกะอยู่ห่างจากชั้นแอปพลิเคชัน ฉันจะดูการกำหนดค่า HAProxy ขอบคุณ!
Ethan Hayon

1
ดีใจที่ได้ช่วยเหลือ การโหวตจะได้รับการชื่นชมถ้าคุณยังไม่ได้ การจำลองแบบวงกลมนั้นมีความน่าเชื่อถือเทียบเท่ากับ master / slave (เป็นเทคโนโลยีเดียวกันเพียงแค่ไปทั้งสองทิศทาง) ตราบใดที่คุณเข้าใจว่ามันทำงานอย่างไรและใช้งานได้อย่างเหมาะสม ตราบใดที่เซิร์ฟเวอร์มีการซิงก์อย่างถูกต้องและแอปพลิเคชันนั้นเขียนไปยังเซิร์ฟเวอร์เพียงหนึ่งครั้งเท่านั้นฉันไม่เคยมีปัญหากับมันเลย auto_increment_*ตัวแปรยังคงดีที่จะใช้ในสถานการณ์นี้ "ในกรณี." นอกจากนี้อย่าลืมใช้binlog_format= rowหรือmixed- ไม่statement(แม้ว่าคุณจะไม่ทำวงกลม)
Michael - sqlbot

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

10

หากคุณใช้ Master / Slave เท่านั้นนี่คือสิ่งที่รวดเร็วและสกปรก:

SELECT COUNT(1) SlaveThreadCount
FROM information_schema.processlist
WHERE user='system user';

สิ่งนี้บอกอะไรคุณ

  • ถ้า SlaveThreadCount = 0 คุณมีปรมาจารย์
  • ถ้า SlaveThreadCount > 0 คุณมี Slave

ข้อแม้ : มันทำงานได้ตราบใดที่คุณไม่ได้วิ่งSTOP SLAVE;

อีกสิ่งที่ควรลองคือ: ถ้าคุณปิดการใช้งานการบันทึกแบบไบนารีบน Slave และคุณเรียกใช้SHOW MASTER STATUS;งาน Master จะให้การบันทึกแบบไบนารีปัจจุบันแก่คุณ ทาสไม่ได้ช่วยอะไรคุณ


เยี่ยมมากนี่คือสิ่งที่ฉันต้องการ คุณคิดว่านี่เป็นวิธีแก้ปัญหาที่ยุ่งหรือเปล่า? ปัญหาเดียวที่ฉันสามารถจินตนาการได้คือเซิร์ฟเวอร์ทั้งสองกำลังได้รับการเลื่อนระดับเป็นต้นแบบ แต่ไม่ควรเกิดขึ้นจริง
Ethan Hayon

หากคำตอบนี้คือสิ่งที่คุณต้องการโปรดทำเครื่องหมายคำตอบที่ยอมรับได้โดยคลิกเครื่องหมายถูกที่คำตอบของฉัน
RolandoMySQLDBA

ฉันไม่สามารถทำเครื่องหมายเป็นที่ยอมรับสำหรับอีก 5 นาที :)
อีธาน Hayon

ไม่มีปัญหา. ฉันดีใจที่ฉันสามารถช่วย !!!
RolandoMySQLDBA

0

รันคำสั่งนี้จากพรอมต์ mysql
mysql> แสดงสถานะทาส;

บนทาสมันแสดงพารามิเตอร์จำนวนมากและค่า / สถานะของพวกเขาในขณะที่ต้นแบบมันแสดงชุดที่ว่างเปล่า

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