Backup LAMP Stacks with LVM Snapshots
I've done a lot with LVM in the past, but up until now had never really played around with LVM snapshots. I recently used LVM snapshots to implement a "hot backup" of my LAMP stack running this blog. I quote "hot backup" because, while mysql is indeed running, I do have to place a read lock on all tables for a second or two. You don't need to do this if you're using Innodb, but you do if you use the MyISAM engine (which Drupal does by default).
The key to doing LVM snapshots is that you save some unassigned space in your volume group when you setup LVM in the first place. If you don't you can shrink existing logical volumes to make space, but that's beyond the scope of this article.
For this article, the following assumptions are made:
- The LVM logical volume we want to back up is /dev/VolGroup00/apps
- The LVM snapshot is named appsnap (clever, huh)
- My personal use of snapshots is to replicate my current production LAMP stack to my development machine. You can use snapshots for just about anything - backup with Amanda or Bacula, or hand-rolled rsync/tar backups like mine. Implementation is the same, it's just the rsync command that you might choose to tweak
How much space does my snapshot logical volume need?
That's a good question, and unfortunately it's one that is answered with another question: "How long will your backup take, and how much writing to your source logical volume will occur during that time?". I would have to assume that 500MB would be good for most setups, but YMMV. In the scripts I present later, our snapshot partition will take whatever is available to the volume group.
Step One: Create the snapshot
Assuming that your MySQL data files reside on the LVM partition that you're snapshotting, and that you're using the MyISAM table engine, we need to temporarily lock the tables. In my particular setup, creating the snapshot takes less than 2 seconds, so it's no big deal to lock my tables for that long. Thanks to commenter Jay on how to fix my bug! Here's the steps:
TMP_FILE="/tmp/msqlbackup-$$.sql" /bin/cat > $TMP_FILE >>EOD FLUSH TABLES WITH READ LOCK; \! /usr/sbin/lvcreate -l100%FREE --snapshot --name appsnap /dev/VolGroup00/apps UNLOCK TABLES; EOD /usr/bin/mysql -u root -pmypasswordAt this point, we have a logical volume at /dev/VolGroup00/appsnap that contains our data exactly as it existed at the time of the lvcreate command above.
Step Two: Mount the snapshot
Pretty straightforward here:
/bin/mkdir /backups /bin/mount /dev/VolGroup00/appsnap /backupsNow, we have our snapshot mounted at /backups. Next, let's back it up.
Step Three: Backup the mountpoint
This step is really up to you. You can tar up the contents, rsync it off somewhere, whatever you feel like doing. If you want to see my rsync command, keep reading.
Step Four: Remove the snapshot
Since the space required by the snapshot gets larger as more writes are made to our apps logical volume, you don't want this thing sitting around long. Let's unmount it, and remove it altogether since we have our data:
/bin/umount /backups /usr/sbin/lvremove -f /dev/VolGroup00/appsnap /bin/rmdir /backupsTada, all done! Pretty painless, really. Now, we're sysadmins, and man, all that typing is for the birds. We need a script!
Tying it all together: Moving prod to dev
First, to make this work well, setup key-based authentication between your dev and prod servers (Google is your friend).
On your production server, we need to create two scripts -- one to create the snapshot, one to remove it. I called mine makelvmsnapshot.sh and removelvmsnapshot.sh. Security Note: I placed my root mysql password in makelvmsnapshot.sh! I'm okay with this, make sure that you are before you do this. We'll set permissions on this file so that only root can see it. Here's the contents of makelvmsnapshot.sh:
#!/bin/bash /bin/mkdir /backups echo "FLUSH TABLES WITH READ LOCK;" | /usr/bin/mysql -u root -pmypassword /usr/sbin/lvcreate -l100%FREE --snapshot --name appsnap /dev/VolGroup00/apps echo "UNLOCK TABLES;" | /usr/bin/mysql -u root -pmypassword /bin/mount /dev/VolGroup00/appsnap /backupsSince our password is in that file, do a 'chown root makelvmsnapshot.sh && chmod 700 makelvmsnapshot.sh' for some very basic security.
Here is my removelvmsnapshot.sh:
#!/bin/bash /bin/umount /backups /usr/sbin/lvremove -f /dev/VolGroup00/appsnap /bin/rmdir /backupsNow, on your dev server, create a script named prod2dev.sh, and place it in /usr/local/bin/. Here's what I have in it:
#!/bin/bash #Stop Services for s in httpd mysqld; do /etc/init.d/$s stop done #Create snapshot lv on prod /usr/bin/ssh root@myprodserver.com /apps/scripts/makelvmsnap.sh #Rsync w/delete /usr/bin/rsync -aHvz --delete --exclude=httpd/log/* root@myprodserver.com:/backups/* /apps/ #Remove snapshot on prod /usr/bin/ssh root@myprodserver.com /apps/scripts/removelvmsnap.sh #Start services for s in httpd mysqld; do /etc/init.d/$s start doneLet's go over that a bit.
- First, I stop mysqld and httpd on my dev server.
- Next, I ssh to the prod server, and call the script that creates the snapshot.
- With the snapshot mounted at /backups in prod, I rsync the contents of prod back to dev (skipping apache access logs).
- Once the rsync is done, I remove the snapshot on production, and start mysqld and httpd on dev.
Conclusion
LVM snapshots are easy, fast, and effective ways to take a slice in time. The hardest part of using LVM snapshots is planning ahead and leaving some free space in your volume group for the snapshot logical volume. By utilizing LVM snapshots you can efficiently replicate setups between machines, or get backups of your LAMP stack. Even more important, you can test the restoration process on a daily basis. Your backups are only as good as your restoration procedure!
Comments
This is a really great
This is a really great article on this. Very nice job, it answered several questions I had about the process.
One thing I am curious about, can you create multiple snapshots for multiple point-in-time recovery?
Trackback
Trackback
Multiple Snapshots
Hey Matt,
Thanks for the comment. You can create multiple snapshots, but I think you're misunderstanding in the same way that I was for some time.
LVM Snapshots aren't so much a snapshot, as they are a real-time diff. Let's say I have a 2TB LVM logical volume, and create a snapshot of that lv. If no changes are made to the source lv, the snapshot lv takes up no space. To expand on that idea, let's say I have a 2TB LVM, and make a snapshot. Next, I create two new 250MB files on the source lv. Now, the snapshot's total size is 500MB, not 2TB! Cool, huh!
So, to answer your question, yes, you can have multiple snapshots, but you probably don't really want them. What you likely want to do, is to keep multiple tar.gz's around after you make backups of the snapshot.
You also mentioned on your blog about how it scales. It scales very well, because it's not making a copy of every file, it's merely keeping track of changes. In the case of a NFS share for a corporate network, you're probably just fine. A very busy database server might see some lag for the lifetime of the snapshot, as basically all writes happen twice as long as the snapshot exists. That's why you create it, do your backup, and delete it.
Hope that clears it up?
It does, thanks! I'm
It does, thanks! I'm definitely going to be playing around with this. Thanks against for posting this article, it's really useful!
Warning - Step One is very wrong!
/usr/sbin/lvcreate -l100%FREE --snapshot --name appsnap /dev/VolGroup00/apps
echo "UNLOCK TABLES;" | /usr/bin/mysql -u root -pmypassword
-----------
In this scenario... the lock is release when the mysql client exits. So you will not be creating a safe and consistent snapshot. You must hold the connection open for the table locks to continue!
Read steps 1-3 and comments 7+8:
http://www.mysqlperformanceblog.com/2006/08/21/using-lvm-for-mysql-backup-and-replication-setup/
Fixed
Thanks for the tip! Fixed.
LVSNAPSHOTS - Giving back.
Hey I wanted to say thanks to you and Jay Yukes for your tips on this subject,
and to give back a little with my alters to this script and usage.
The script is not 100% fully automated and a little more tweaking is needed for me at least, but this is what I use.
#set -x
LV=`lvdisplay | grep 'dev' | grep -v 'Block' | grep -v 'root' | awk '{ print $3 }'`
#LV3=`lvdisplay | grep 'dev' | grep -v 'Block' | grep -v 'root' | awk '{ print $3 }' | sed 's/\/VolGroup00-ext//g'`
LV2=`lvdisplay | grep 'dev' | grep -v 'Block' | grep -v 'root' | awk '{ print $3 }' | sed 's/\/ext//g'`
mysql < < QUERY_INPUTFLUSH TABLES; FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS;\! lvcreate -L16G -s -n dbbackup ${LV}UNLOCK TABLES;\! mount ${LV2}/dbbackup /ext/backup\! rsync -vaz --progress --stats --exclude="mysql-bin.*" --exclude="mysql-relay.*" /ext/backup/db/ USER@xxx.xxx.xxx.xxx:/ext/db/\! umount /ext/backup\! lvremove -f ${LV2}/dbbackupQUERY_INPUTOk so the output of this script gives me my mysql-bin and offset.
.scripts# ./lvsnap3.sh
File Position Binlog_Do_DB Binlog_Ignore_DB
mysql-bin.002185 44084495
File descriptor 3 left open
Logical volume "dbbackup" created
So I will apply that information when the script is completed on my slave server as follows.
stop slave;
CHANGE MASTER TO MASTER_HOST='xxx.xxx.xxx.xxx',MASTER_USER='replication', MASTER_PASSWORD='slave-password',MASTER_LOG_FILE='mysql-bin.002185', MASTER_LOG_POS=44084495;
start slave;
mysql> show slave status\G
To check replication current status.
I thought I would include a script as well that I remember reading from your site, something about bash and `seq 1 10` You can also use something like this as well.
1
3
5
7
9
11
13
15
17
19
or in a script, bash like arrays to loop through your servers.
#! /bin/bash
NAME=( tst1 dbm1 )
for SERVER in ${NAME[@]}; do
ssh ${SERVER} $1;
done
I myself enjoy the cmd one-liners.I will sometimes use something like this for adding users to many servers.
This method and example will not work with all flavors of linux, and setups, YOU will have to test this first in a non production ENV.
The new admin will also be forced to change his password after he first logs in.
Regards,
Kurt Larsen
Add new comment