วิธีที่ปลอดภัยที่สุดในการใช้ mysqldump บนระบบจริงที่มีการอ่านและเขียนที่ใช้งานอยู่?


78

ฉันไม่แน่ใจว่าสิ่งนี้จริงหรือไม่ แต่ฉันจำได้ว่าอ่านถ้าคุณเรียกใช้คำสั่งต่อไปนี้ใน linux

mysqldump -u username -p database_name > backup_db.sql

ขณะที่กำลังอ่านและเขียนข้อมูลกับฐานข้อมูลดังนั้นดัมพ์อาจมีข้อผิดพลาด

มีตัวเลือกเฉพาะในคำสั่งmysqldumpเพื่อให้แน่ใจว่าทำได้อย่างปลอดภัยบนระบบจริงหรือไม่? ฉันโอเคที่มีการอ่าน / เขียนถูกปิดการใช้งานสำหรับผู้ใช้ของเราสองสามวินาที (ฐานข้อมูล <50MB)

คำตอบ:


82

ข้อมูลทั้งหมดคือ InnoDB

นี่คือสิ่งที่จะทำให้คุณได้รับข้อมูล ณ จุดเวลาที่แน่นอน:

mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

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

--routines ดัมพ์โพรซีเดอร์ที่เก็บไว้ทั้งหมดและฟังก์ชันที่เก็บไว้

--triggers ทิ้งทริกเกอร์ทั้งหมดสำหรับแต่ละตารางที่มี

ข้อมูลทั้งหมดคือ MyISAM หรือส่วนผสมของ InnoDB / MyISAM

คุณจะต้องกำหนดล็อกการอ่านระดับโลกดำเนินการ mysqldump และปลดล็อคระดับโลก

mysql -uuser -ppass -Ae"FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400)" &
sleep 5
mysql -uuser -ppass -ANe"SHOW PROCESSLIST" | grep "SELECT SLEEP(86400)" > /tmp/proclist.txt
SLEEP_ID=`cat /tmp/proclist.txt | awk '{print $1}'`
echo "KILL ${SLEEP_ID};" > /tmp/kill_sleep.sql
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql
mysql -uuser -ppass -A < /tmp/kill_sleep.sql

ให้มันลอง !!!

อัพเดท 2012-06-22 08:12 EDT

เนื่องจากคุณมีข้อมูลทั้งหมด <50MB ฉันมีตัวเลือกอื่น แทนที่จะเรียกใช้คำสั่ง SLEEP เป็นพื้นหลังเพื่อเก็บล็อกการอ่านส่วนกลางสำหรับ 86400 วินาที (ที่ 24 ชั่วโมง) เพียงเพื่อรับ ID กระบวนการและกำจัดข้างนอกลองตั้งค่าไทม์เอาต์ 5 วินาทีใน mysql แทนใน OS:

SLEEP_TIMEOUT=5
SQLSTMT="FLUSH TABLES WITH READ LOCK; SELECT SLEEP(${SLEEP_TIMEOUT})"
mysql -uuser -ppass -Ae"${SQLSTMT}" &
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

นี่เป็นวิธีที่สะอาดและง่ายกว่าสำหรับฐานข้อมูลขนาดเล็กมาก


1
5 วินาทีเป็นเพียงข้อควรระวัง คุณสามารถลองลดค่า
RolandoMySQLDBA

1
Rolando - เป็นERROR 2013 (HY000) at line 1: Lost connection to MySQL server during queryข้อความแสดงข้อผิดพลาดที่คาดหมายหรือไม่
user784637

1
ข้อมูล MySQL ทั้งหมดออกมาใน mysqldump หรือไม่?
RolandoMySQLDBA

1
ฉันไม่แน่ใจเกี่ยวกับข้อความแสดงข้อผิดพลาด นี่เป็นเพียงการคาดเดา แต่นั่นอาจมาจากสคริปต์บรรทัดเดียวที่ฆ่าการเรียกใช้ฟังก์ชัน SLEEP ที่ผู้ใช้กำหนดเองที่ฉันพูดถึงในสคริปต์ที่สอง
RolandoMySQLDBA

1
ลองคำแนะนำใหม่ของฉันและดูว่าเป็นไปด้วยดีไหม หวังว่าจะไม่มีข้อความแสดงข้อผิดพลาด
RolandoMySQLDBA


1

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


1

นี่เป็นวิธีที่ฉันทำ FLUSH TABLES WITH READ LOCKมันควรจะทำงานในทุกกรณีเพราะใช้

#!/bin/bash

DB=example
DUMP_FILE=export.sql

# Lock the database and sleep in background task
mysql -uroot -proot $DB -e "FLUSH TABLES WITH READ LOCK; DO SLEEP(3600);" &
sleep 3

# Export the database while it is locked
mysqldump -uroot -proot --opt $DB > $DUMP_FILE

# When finished, kill the previous background task to unlock
kill $! 2>/dev/null
wait $! 2>/dev/null

echo "Finished export, and unlocked !"

sleepคำสั่งเชลล์เพียงเพื่อให้แน่ใจว่างานแบ็คกราวน์ที่รันคำสั่งการล็อค mysql นั้นได้รับการดำเนินการก่อนที่จะเริ่ม mysqldump คุณสามารถลดความมันลงไปได้ 1 วินาทีและมันก็ยังใช้ได้อยู่ เพิ่มเป็น 30 วินาทีและลองแทรกค่าในตารางใด ๆ จากไคลเอนต์อื่นในช่วง 30 วินาทีที่คุณจะเห็นว่ามันถูกล็อค

มีข้อดี 2 ข้อในการใช้การล็อกพื้นหลังแบบแมนนวลแทนที่จะใช้mysqldumpตัวเลือก--single-transactionและ--lock-tables:

  1. สิ่งนี้จะล็อคทุกอย่างถ้าคุณผสมตาราง MyISAM / InnoDB
  2. คุณสามารถรันคำสั่งอื่นนอกเหนือจากในmysqldumpช่วงเวลาล็อคเดียวกัน ตัวอย่างเช่นมีประโยชน์เมื่อตั้งค่าการจำลองแบบบนโหนดหลักเนื่องจากคุณจำเป็นต้องได้รับตำแหน่งบันทึกไบนารีด้วยSHOW MASTER STATUS;ที่สถานะที่แน่นอนของการถ่ายโอนข้อมูลที่คุณสร้างขึ้น (ก่อนปลดล็อกฐานข้อมูล) เพื่อให้สามารถสร้างทาสการจำลองแบบ

1

ข้อเสนอแนะของเอกสารอย่างเป็นทางการของ mysql คือคุณควรมีฐานข้อมูล Master "M1" และฐานข้อมูล Slave "S1" ซึ่งอธิบายไว้ใน "สถานการณ์ที่ 2: การสำรองข้อมูลด้วย Slave แบบอ่านอย่างเดียว" การ สำรอง Master หรือ Slave โดยการทำ อ่านเท่านั้น

คุณควรตั้งค่าฐานข้อมูลทาสให้อ่านอย่างเดียวและดำเนินการ


0

หากคุณมีตาราง MYISAM ที่ใหญ่มากและคุณต้องดัมพ์ตารางโดยไม่มีการล็อกและหลีกเลี่ยงการโหลดเซิร์ฟเวอร์สูงคุณสามารถใช้สคริปต์ต่อไปนี้

#!/bin/sh

my_user="user"
my_password="password"
my_db="vpn"
my_table="traffic"
my_step=100000

read -p "Dumping table ${my_db}.${my_table} to ${my_table}.sql?" yn
case $yn in
    [Yy]* ) break;;
    * ) echo "User cancel."; exit;;
esac

my_count=$(mysql $my_db -u $my_user -p$my_password -se "SELECT count(*) FROM $my_table")
my_count=$(($my_count + 0))

if [ ! $my_count ]
then
    echo "No records found"
    exit
fi

echo "Records in table ${my_db}.${my_table}: ${my_count}"

echo "" > $my_table.sql

max_progress=60

for (( limit=0; limit<=$my_count; limit+=$my_step )); do
    progress=$((max_progress * ( limit + my_step) / my_count))

    echo -ne "Dumping ["
    for ((i=0; i<$progress; i ++)); do
        echo -ne "#"
    done
    for ((; i<$max_progress; i ++)); do
        echo -ne "."
    done

    mysqldump -u $my_user -p$my_password --complete-insert --no-create-info --opt --where="1 limit $limit , $my_step" $my_db $my_table >> $my_table.sql
    echo "" >> $my_table.sql

    echo -ne "] $((100 * ( limit + my_step ) / my_count)) %"
    echo -ne "\r"

    sleep 1

done

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