其乐融融的IT技术小站

一个案例讲明白!如何更安全地实现数据备份和恢复

本文转载自微信公众号「数仓宝贝库」,作者李玥  。转载本文请联系数仓宝贝库公众号。

保证数据安全,最简单且有效的方法就是定期备份数据,这样无论因为出现何种问题而导致的数据损失,都可以通过备份来恢复数据。但是,如何备份才能最大程度地保证数据安全,并不是一件简单的事情。

2018年曾出现过一次重大故障,某著名云服务商因为硬盘损坏,导致多个客户数据全部丢失。通常来说,一个大的云服务商,数据通常都会有多个备份,即使硬盘损坏,也不会导致数据丢失的重大事故,但是因为各种各样的原因,最终的结果是数据的三个副本都被删除,数据丢失无法找回。

所以,并不是简单地定期备份数据就可以高枕无忧了。下面就以最常用的MySQL为例来讲解,如何更安全地实现数据的备份和恢复。

最简单的备份方式就是全量备份。备份的时候,把所有的数据复制一份,存放到文件中,恢复的时候再把文件中的数据复制回去,这样就可以保证恢复之后,数据库中的数据与备份时的数据是完全一样的。在MySQL中,我们可以使用mysqldump命令执行全量备份。

比如,全量备份数据库test的命令如下:

  1. 1$mysqldump -uroot -p test > test.sql 

备份出来的文件是一个SQL文件,文件的内容就是创建数据库、表,写入数据等之类的SQL语句,如果要恢复数据,则直接执行这个备份的SQL文件就可以了:

  1. $mysql -uroot test < test.sql 

不过,全量备份的代价非常高,为什么这么说呢?

首先,备份文件包含了数据库中的所有数据,占用的磁盘空间非常大;其次,每次备份操作都要拷贝大量的数据,备份过程中会占用数据库服务器大量的CPU和磁盘IO资源。同时,为了保证数据一致性,备份过程中很有可能会锁表。这些都会导致在备份期间,数据库本身的性能严重下降。所以,我们不能频繁地对数据库执行全量备份操作。

一般来说,在生产系统中,每天执行一次全量备份就已经是非常频繁的了。这就意味着,如果数据库中的数据丢失了,就只能恢复到最近一次全量备份的那个时间点,这个时间点之后的数据是无法找回的。也就是说,因为全量备份的代价比较高,不能频繁地执行备份操作,所以全量备份不能做到完全无损的恢复。

既然全量备份代价太高,不能频繁执行,那么有没有代价较低的备份方法,能让我们的数据少丢失甚至不丢失呢?增量备份可以达到这个目的。相比于全量备份,增量备份每次只用备份相对于上一次备份发生了变化的那部分数据,所以增量备份的速度更快。

MySQL自带的Binlog,就是一种实时的增量备份工具。Binlog所记录的就是MySQL数据变更的操作日志。开启Binlog之后,MySQL中数据的每次更新操作,都会记录到Binlog中。Binlog是可以回放的,回放Binlog,就相当于是把之前对数据库中所有数据的更新操作,都按顺序重新执行一遍,回放完成之后,数据自然就恢复了。这就是Binlog增量备份的基本原理。很多数据库都有类似于MySQL Binlog的日志工具,原理也与Binlog相同,备份和恢复的方法也与之类似。

下面就来通过一个例子,讲解如何使用Binlog进行备份和恢复。首先,使用“show variables like '%log_bin%'”命令确认一下是否开启了Binlog功能:

  1.  1mysql> show variables like '%log_bin%'
  2.  2 
  3.  3+---------------------------------+-----------------------------------+ 
  4.  4 
  5.  5| Variable_name                   | Value                             | 
  6.  6 
  7.  7+---------------------------------+-----------------------------------+ 
  8.  8 
  9.  9| log_bin                         | ON                                | 
  10. 10 
  11. 11| log_bin_basename                | /usr/local/var/mysql/binlog       | 
  12. 12 
  13. 13+---------------------------------+-----------------------------------+ 
  14. 14 
  15. 15mysql> show master status; 
  16. 16 
  17. 17+-------------+--------+------------+----------------+-----------------+ 
  18. 18 
  19. 19| File        |Position|Binlog_Do_DB|Binlog_Ignore_DB|Executed_Gtid_Set| 
  20. 20 
  21. 21+-------------+--------+------------+----------------+-----------------+ 
  22. 22 
  23. 23|binlog.000001|   18745|            |                 |                 | 
  24. 24 
  25. 25+-------------+--------+------------+----------------+-----------------+ 
  26. 26 

我们可以看到,当前这个数据库已经开启了Binlog,log_bin_basename表示Binlog文件在服务器磁盘上的具体位置。然后,我们用“show master status”命令查看当前Binlog的状态,结果显示了正在写入的Binlog文件,以及其当前的位置。假设我们每天凌晨用mysqldump做一个全量备份,然后开启Binlog,借助于这些备份操作,我们可以把数据恢复到全量备份之后的任意一个时刻。

下面就来做一个简单的备份恢复演示。我们先模拟一次“删库跑路”的场景,直接把账户余额表清空:

  1. 1mysql> truncate table account_balance; 
  2. 3Query OK, 0 rows affected (0.02 sec) 
  3. 5mysql> select * from  account_balance; 
  4. 7Empty set (0.00 sec) 

然后进行数据恢复,首先执行一次全量恢复,把数据库恢复到当天凌晨的状态:

  1.  1$mysql -uroot test < dump.sql 
  2.  2 
  3.  3mysql> select * from  account_balance; 
  4.  4 
  5.  5+---------+---------+---------------------+--------+ 
  6.  6 
  7.  7| user_id | balance | timestamp           | log_id | 
  8.  8 
  9.  9+---------+---------+---------------------+--------+ 
  10. 10 
  11. 11|       0 |     100 | 2020-02-13 20:24:33 |      3 | 
  12. 12 
  13. 13+---------+---------+---------------------+--------+ 

可以看到,表里面的数据已经恢复了,但还是比较旧的数据。接下来,我们再用Binlog把数据恢复到“删库跑路”之前的那个时刻:

  1.  1$mysqlbinlog --start-datetime "2020-02-20 00:00:00" --stop-datetime "2020-02-20 15:09:00" /usr/local/var/mysql/binlog.000001 | mysql -uroot 
  2.  2 
  3.  3mysql> select * from  account_balance; 
  4.  4 
  5.  5+---------+---------+---------------------+--------+ 
  6.  6 
  7.  7| user_id | balance | timestamp           | log_id | 
  8.  8 
  9.  9+---------+---------+---------------------+--------+ 
  10. 10 
  11. 11|       0 |     200 | 2020-02-20 15:08:12 |      0 | 
  12. 12 
  13. 13+---------+---------+---------------------+--------+ 
  14. 14 

由恢复结果可以看出,数据已经恢复到当天的15点了。

通过定期的全量备份,配合Binlog,我们可以把数据恢复到任意一个时间点,再也不怕程序员“删库跑路”了。详细的命令,可以参考MySQL官方文档中的“备份和恢复”相关章节。

在执行备份和恢复的时候,大家需要特别注意如下两个要点。

第一,也是最重要的,“不要把所有的鸡蛋放在同一个篮子中”,无论是全量备份还是Binlog,都不要与数据库存放在同一个服务器上。最好能存放到不同的机房,甚至不同城市,离得越远越好。这样即使出现机房着火、光缆被挖断甚至地震也不怕数据丢失。

第二,在回放Binlog的时候,指定的起始时间可以比全量备份的时间稍微提前一点儿,这样可以确保全量备份之后的所有操作都在恢复的Binlog范围内,从而保证数据恢复的完整性。

因为回放Binlog的操作是具备幂等性的(为了确保回放的幂等性,需要将Binlog的格式设置为ROW格式)。

关于作者:李玥,美团基础技术部高级技术专家,极客时间《后端存储实战课》《消息队列高手课》等专栏作者。曾在当当网、京东零售等公司任职。从事互联网电商行业基础架构领域的架构设计和研发工作多年,曾多次参与双十一和618电商大促。专注于分布式存储、云原生架构下的服务治理、分布式消息和实时计算等技术领域,致力于推进基础架构技术的创新与开源。

 

本文摘编自《电商存储系统实战:架构设计与海量数据处理》,经出版方授权发布。(ISBN:9787111697411)转载请保留文章出处。

 

赞 ()
分享到:更多 ()

相关推荐

内容页底部广告位3
留言与评论(共有 0 条评论)
   
验证码: