如何在两台服务器之间安全迁移MySQL数据库

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在两台服务器之间安全迁移MySQL数据库相关的知识,希望对你有一定的参考价值。

   迁移MySQL数据库通常只需要几个简单的步骤,但是由于您要转移的数据量可能比较庞大,因此一般耗时也会比较长。

 

     

 

    下面的步骤将指导您如何从旧的服务器上导出MySQL数据库,对它进行安全加固;然后将其复制并导入到新的服务器上,以保证数据的完整。

 

    将MySQL数据库导出至转储文件(dump file)

 

    Oracle提供了一个名为mysqldump的工具,允许您轻松地将数据库结构和其数据导出到一个SQL的转储文件。您可以使用如下的命令:

 

    1.mysqldump -u root -p --opt [database name] > [database name].sql 

 

    不过,请注意如下几点:

 

    我们可以使用--single-transaction的标志,以避免数据库在导出数据的过程中被锁死。这样能够在将数据导出到转储文件的同时,您仍可继续在旧的数据库上更新数据。不过请注意,那些在导出进程已经开始之后被更新的数据,是不会被导入转储文件之中的。

 

    在运行该命令之前,请务必将[database name]替换成您的实际数据库名称。

 

    请输入您自己的用户名和相对应的密码,并确保该用户具有备份数据库所需的权限。

 

    安全加固备份文件

 

    在大多数情况下,数据是一家企业的最重要的资产。因此,我们不希望数据库的各种备份被暴露在不受保护的服务器上,因为这样有可能会造成错误地泄露,甚至会出现被黑客窃取等更为糟糕的状况。

 

    因此,通常您可以尝试的做法是:压缩、加密文件,然后删除原文件。在Linux操作系统上,请使用以下的命令对已压缩文件进行加密:

 

    1.zip --encrypt dump.zip db.sql 

 

    在压缩开始之前,系统将提示您输入密码。

 

    传输备份文件

 

    至此,我们已经获得了一个加密的转储文件。下面让我们通过网络使用SCP命令,将其传输到新的服务器上:

 

    1.scp /path/to/source-file user@host:/path/to/destination-folder/ 

 

    将MySQL转储导入新服务器

 

    通过上面一步,我们已将备份文件传到了新的服务器上,下面让我们来进行解密和提取:

 

    1.unzip -P your-password dump.zip 

 

    为了存储空间和安全方面的原因,一旦文件导入成功,请记得删除其对应的转储文件。

 

    您可以使用以下的命令来导入文件:

 

    1.mysql -u root -p newdatabase < /path/to/newdatabase.sql 

 

    在新服务器上验证导入的数据

 

    现在我们在新服务器上已经导入了数据库,那么我们就需要一种方法来验证数据的真实存在,并确保没有任何遗漏。

 

    我建议您同时在旧的和新的数据库上运行如下查询,并将获得的结果进行对比。

 

    该查询会在所有的表里计算行数,以显示出新、旧数据库中的数据量。

 

    1.SELECT   

    

    2.TABLE_NAME,   

    

    3.TABLE_ROWS  

 

    4.FROM   

    `

    5.information_schema`.`tables`  

 

    6.WHERE   

    `

    7.table_schema` = 'YOUR_DB_NAME'; 

 

    此外,我建议您检查各个表中数字列的MIN和MAX记录,以确保数据本身是有效的,而不仅仅是看数据的总量(虽然这是查询所唯一能够读出的值)。另一种可供测试的选择是将数据库从新的服务器导出为SQL转储文件,并将其与旧服务器的SQL转储文件做比较。

 

    此外,在应用程序被迁移之前,我建议您先将一个应用程序的实例重定向到新的数据库上,以确认一切运行正常。

 

    另一种导出和导入的选项

 

    我们之所以把该选项放在最后,是因为我们的确不建议您去使用它。

 

    该方法实现起来非常的容易,因为它仅使用一个命令,便能一次性将转储文件导出、传输、并将其数据导入到新的数据库之中。

 

    而它的不足之处在于,一旦其网络链接断掉,您就需要重新启动它了。

 

    因此,我们认为它并不值得被推荐,尤其是在大型数据库中,可能会非常不适用。

 

    当然,如果您非要尝试一下的话,可以使用如下的命令:

 

    1.mysqldump -u root -pPassword --all-databases | ssh user@new_host.host.com 'cat - | mysql -u root -pPassword' 

 

    重要提示

 

    请确保在新旧两处,安装有相同官方发行版本的MySQL服务器。否则,你需要按照MySQL网站上的升级说明来进行统一(请参见(https://dev.mysql.com/doc/refman/5.7/en/upgrading.html)。

 

    请确保您在旧的服务器上拥有足够的空间来保存转储文件和压缩文件(应该有db_size×2的空间)。

 

    请确保您在新的服务器上拥有足够的空间来保存加密的和解密的转储文件、并能导入数据库(应该有db_size×3的空间)。

 

    如果您曾经考虑过只是将datadir从一个数据库转移到另一个的话,我建议您最好不要这样做。否则,您会搞乱数据库的内部结构,而且会给将来可能的问题埋下隐患。

 

    在新的服务器配置中,请不要忘了配置诸如innodb_log_file_size这样的重要标志。因为如果忘记了根据新服务器的规格而更新配置的话,很可能会导致严重的性能问题。

 

    在许多情况下,一般升级到新的数据库服务器的初衷是为了提高查询性能。而如果此类升级没有达到预期的改善,那么您就应该考虑去优化SQL查询,而不仅仅是升级硬件那么简单了

参考技术A

    caching_sha2_password认证插件提供更多的密码加密方式,并且在加密方面具有更好的表现,目前mysql 8.0选用caching_sha2_password作为默认的认证插件,MySQL 5.7的认证插件是MySQL_native_password。如果客户端版本过低,会造成无法识别MySQL 8.0的加密认证方式,最终导致连接问题。

    MySQL存储引擎现在负责提供自己的分区处理程序,而MySQL服务器不再提供通用分区支持,InnoDB和NDB是唯一提供MySQL 8.0支持的本地分区处理程序的存储引擎。 如果分区表用的是别的存储引擎,存储引擎必须进行修改。要么将其转换为InnoDB或NDB,要么删除其分区。通过MySQLdump从5.7获取的备份文件,在导入到8.0环境前,需要确保创建分区表语句中指定的存储引擎必须支持分区,否则会报错。

    MySQL 8.0的默认字符集utf8mb4,可能会导致之前数据的字符集跟新建对象的字符集不一致,为了避免新旧对象字符集不一致的情况,可以在配置文件将字符集和校验规则设置为旧版本的字符集和校验规则。

    MySQL 8.0启动使用的lower_case_table_names值必须跟初始化时使用的一致。使用不同的设置重新启动服务器会引入与标识符的排序和比较方式不一致的问题。

    < lower_case_table_names >

    https://dev.mysql.com/doc/refman/8.0/en/server-systemvariables.html#sysvar_lower_case_table_names

    要避免MySQL 8.0上的启动失败,MySQL配置文件中的sql_mode系统变量不能包含NO_AUTO_CREATE_USER。

    从MySQL 5.7.24和MySQL 8.0.13开始,MySQLdump从存储程序定义中删除了NO_AUTO_CREATE_USER。必须手动修改使用早期版本的MySQLdump创建的转储文件,以删除NO_AUTO_CREATE_USER。

    在MySQL 8.0.11中,删除了这些不推荐使用的兼容性SQL Mode:DB2,MAXDB,MSSQL,MySQL323,MySQL40,ORACLE,POSTGRESQL,NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS。从5.7到8.0的复制场景中,如果语句使用到废弃的SQL Mode会导致复制异常。

    在执行到MySQL 8.0.3或更高版本的in-place升级时,BACKUP_ADMIN权限自动授予具有RELOAD权限的用户。 

    本文对MySQL 5.7到MySQL 8.0的升级过程中出现部分易出现问题进行整理:升级对MySQL版本的要求、升级都做了哪些内容、数据库升级做了哪些步骤以及注意事项,希望对大家版本升级有帮助。

如何使用 RequestBody 和 PostMapping 在两台服务器之间共享数据?

【中文标题】如何使用 RequestBody 和 PostMapping 在两台服务器之间共享数据?【英文标题】:How to share data between two server using RequestBody and PostMapping? 【发布时间】:2021-10-14 04:45:30 【问题描述】:

我正在尝试使用 ResponseEntity 在 Spring Boot 中将数据从一台服务器 (8081) 共享到另一台服务器 (8082),但我无法构建主体。

这是我写的代码,

服务器 1-

    @GetMapping("/redirect")
    public ResponseEntity<Void> redirectPgServer(@RequestParam("txnId") String txnId, 
    @RequestParam("amount") String amount) 

    // Redirect to server 2
    ProductDetails ref=new ProductDetails();
    ref.setTxnId("txnId");
    ref.setAmount("amount);
    HttpHeaders head = new HttpHeaders();
    String url = "http://localhost:8082/redirect-server";                                                                                                       
    System.out.println(url);
    head.setLocation(URI.create(url));
    return new ResponseEntity<Void>(ref, head, HttpStatus.FOUND);

服务器2-

 @GetMapping(value = "/redirect-server")
 public String validateData(@RequestBody ProductDetails ref)

    //Server 2 receive data
      System.out.println(ref.getAmount());  

 //Does not gives any output since it throws error Request Body Missing, also if I mention 
  post mapping above it throws error Request method 'GET' not supported]

     return "index";   //Using Thymeleaf for displaying html page.
   

我可以通过操纵 url 和使用 PathVariable 仅使用 header 共享数据,但我想使用 Post Mapping 因为我想隐藏参数在浏览器中对用户可见的 URL。我还尝试使用 RestTemplate 将我带回服务器 1 并引发错误 - Spring rest 模板无法从 text/html utf8 转换

【问题讨论】:

这个问题不完整。这里没有通讯。只有一个定义的端点,另一个似乎什么都不做的端点。缺少的部分很可能是您遇到问题的地方。 您很可能需要将ResponseEntity&lt;Void&gt; 更改为ResponseEntity&lt;ProductDetails&gt; 【参考方案1】:

我的建议是用@PostMapping 注释这两种方法,同时删除@RequestBody 注释。在第一个服务器中,您应该使用 307 HTTP 代码(这是临时重定向)进行响应,基本上这会告诉浏览器,重试对另一个端点的调用(在 Location 标头中给出)。

类似这样的:

服务器 1

 @PostMapping(value = "/redirect", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public ResponseEntity redirect(Product product) 
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setLocation(URI.create("http://localhost:8082/product"));
        return new ResponseEntity(httpHeaders, HttpStatus.TEMPORARY_REDIRECT);
    

服务器 2

@PostMapping(value = "/product", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void redirect(Product prod) 
    System.out.println(prod.getId());
    //do your stuff

HTML 页面

<html>
    <body>
        <form action="http://localhost:8081/redirect" method="POST">
            <input name="id">
            <input name="name">
            <button type="submit">Send</button>
         </form>
    </body>
</html>

如果您不使用表单,而是使用某种异步调用,您必须指定 url 表单编码。否则你会得到一个 405。

我已经用邮递员和一个 html 页面尝试过代码,它确实可以正常工作。 (用 Firefox 试过)

如果有不清楚的地方不要问。

我发现了一个类似的问题,我从中获得了灵感 A good way to redirect with a POST request?

【讨论】:

以上是关于如何在两台服务器之间安全迁移MySQL数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 RequestBody 和 PostMapping 在两台服务器之间共享数据?

企业如何成功完成云迁移?

如何在都需要密码的 Postgres 服务器之间迁移数据? [复制]

RedHat 7 KVM虚拟机在两台宿主机之间在线迁移

C#如何在两台服务器之间进行通信

在两台计算机之间移动连接和实例