
# 使用DCS改造传统应用系统数据库
#### 方案概述
**应用场景**
随着互联网等数据库应用行业的逐渐发展，业务需求急速增加，数据量和并发访问量呈指数级增长，仅依附于传统关系型数据库难以支撑上层业务。传统数据库存在结构复杂、维护成本高、访问性能差、功能有限、无法轻松适应数据模型或模式的变化等问题。
**解决方案**
将Redis作为应用与数据库之间的缓存层可以解决上述问题，通过Redis缓存数据，提高数据读取速度，减轻数据库负载，提高应用性能，保证数据的可靠性。
因此，对于传统的关系型数据库例如MySQL，可以将其数据迁移到Redis中。Redis中的数据是以键值结构进行存储的，在迁移前需要将传统的数据库转换为特定的结构。本文以将MySQL数据库中的一张表迁移到华为云DCS Redis中为例，介绍数据迁移的过程。
#### 前提条件
- 已创建DCS Redis实例，作为迁移的目的数据库。请参考[创建DCS Redis缓存实例](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0713002.html)。
  ![](https://support.huaweicloud.com/bestpractice-dcs/public_sys-resources/note_3.0-zh-cn.png)
  如果您的源端是华为云的MySQL数据库，Redis实例请选择与MySQL数据库实例相同的VPC。
  
- 已有MySQL数据库，并在其中创建一张表，作为源端数据库中的数据。 例如，在MySQL数据库中创建一张名为student_info的表格，表中共有4列，迁移后表中的id列的值将成为Redis中的hash的key，其余的列名将成为hash的field，而列的值作为field对应的value。
  ![](https://support.huaweicloud.com/bestpractice-dcs/zh-cn_image_0000001636527549.png "点击放大")
  
- MySQL数据库所在服务器与DCS缓存实例网络互通。
  - MySQL数据库与Redis实例所在VPC为同一VPC 同一VPC内网络默认互通。
    
  
  - MySQL数据库与Redis实例所在VPC为相同region下的不同VPC 如果MySQL数据库所在VPC与Redis实例不在相同VPC中，可以通过建立VPC对等连接方式连通网络，具体请参考：[缓存实例是否支持跨VPC访问？](https://support.huaweicloud.com/dcs_faq/dcs-faq-0427002.html)。
    
  
  - MySQL数据库与Redis实例所在VPC不在相同region 如果MySQL数据库和Redis实例不在同一region，仅支持通过云专线打通网络，请参考[云专线](https://support.huaweicloud.com/productdesc-dc/zh-cn_topic_0032053183.html)。
    
  
  - 公网访问 MySQL数据库所在服务器公网访问Redis 4.0/5.0/6.0实例时，需要开启实例公网访问开关，具体请参考[开启Redis 4.0/5.0/6.0公网访问并获取公网访问地址](https://support.huaweicloud.com/usermanual-dcs/dcs_03_0011.html)。
    
   
- MySQL数据库所在服务器已安装[JDK1.8](https://www.oracle.com/java/technologies/downloads/)以上版本和[Intellij IDEA](https://www.jetbrains.com/idea/)开发工具，下载jedis客户端（[点此处下载jar包](https://jar-download.com/artifacts/redis.clients/jedis/3.5.1/source-code)）。
  本文档下载的开发工具和客户端仅为示例，您可以选择其它类型的工具和客户端。
  
 
#### 实施步骤
1. 登录MySQL数据库所在服务器。
2. 在MySQL数据库所在服务器安装Redis客户端用来进行数据的提取、传输和转换。安装Redis客户端请参考[安装Redis客户端](https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0713004.html#section1)。
3. 分析源端数据结构，在MySQL数据库所在服务器中创建如下的迁移脚本，保存文件名为migrate.sql。 
   ```
   SELECT CONCAT(
   "*8\r\n",  #这里的8是下方字段的数量，由MySQL表中的数据结构决定
   '$', LENGTH('HMSET'), '\r\n',  #HMSET是在Redis中写入数据时使用的命令
   'HMSET', '\r\n',
   '$', LENGTH(id), '\r\n',   #id是HMSET字段后的第一个字段，迁移后会成为Redis Hash中的key
   id, '\r\n',
   '$', LENGTH('name'), '\r\n',   #'name'将以字符串形式传入hash中，作为其中一个field。下面的'birthday'等与它相同
   'name', '\r\n',
   '$', LENGTH(name), '\r\n',  #name是一个变量，代表了MySQL表中公司的名称，迁移后会成为上一参数'name'生成的field所对应的value。下面的birthday等与它相同
   name, '\r\n',
   '$', LENGTH(' birthday'), '\r\n',
   ' birthday', '\r\n',
   '$', LENGTH(birthday), '\r\n',
   birthday, '\r\n',
   '$', LENGTH('city'), '\r\n',
   'city', '\r\n',
   '$', LENGTH(city), '\r\n',
   city, '\r'
   )
   FROM student_info AS s
   ```
   
   
4. 在MySQL数据库所在服务器中使用如下命令迁移数据。 
   ```
   mysql -h <MySQL host> -P <MySQL port> -u <MySQL username> -D <MySQL database name> -p --skip-column-names --raw < migrate.sql | redis-cli -h <Redis host> -p<Redis port> --pipe  -a <Redis password>
   ```
   表1参数项说明 
   | 参数项                 | 说明                                                                                                 | 示例                     |
   |:---|:---|:---|
   | -h                  | MySQL数据库的连接地址。                                                                                     | xxxxxx                 |
   | -P                  | MySQL的服务端口。                                                                                        | 3306                   |
   | -u                  | MySQL的用户名。                                                                                         | root                   |
   | -D                  | 待迁移的表所在的库。                                                                                         | mysql                  |
   | -p                  | MySQL的连接密码。如果没有密码，-p后为空。 为了提高安全性，可以只输入-p，不在其后输入密码，执行命令后再根据命令行提示输入密码。 | xxxxxx                 |
   | --skip-column-names | 不在查询结果中写入列名。                                                                                       | 无需设置                   |
   | --raw               | 输出列的值时不进行转义。                                                                                       | 无需设置                   |
   | Redis-cli之后的-h      | Redis的连接地址。                                                                                        | redis-xxxxxxxxxxxx.com |
   | Redis-cli 后的-p      | Redis的端口。                                                                                          | 6379                   |
   | --pipe              | 使用Redis的Pipeline功能进行传输。                                                                            | 无需设置                   |
   | -a                  | Redis的连接密码。如果没有密码则不需设置。                                                                            | xxxxxx                 |
      
   ![](https://support.huaweicloud.com/bestpractice-dcs/zh-cn_image_0000001636200533.png "点击放大")
   上图中以Redis实例没有设置密码为例，执行结果中的errors表示执行过程中的错误数，replies表示收到的回复数。如果errors为0，且replies与MySQL表中的记录数相同，则整表迁移成功。
   
   
5. 迁移完成后，一条MySQL数据对应一条Redis的Hash数据。可以连接Redis后用HGETALL命令查询验证。结果如下： 
   ```
   [root@ecs-cmtest mysql-8.0]# redis-cli -h redis-xxxxxxxxxxxx.com -p 6379
   redis-xxxxxxxxxxxx.com:6379> HGETALL 1
   1) "name"
   2) "Wilin"
   3) " birthday"
   4) "1995-06-12"
   5) "city"
   6) "Nanjing"
   redis-xxxxxxxxxxxx.com:6379> HGETALL 4
   1) "name"
   2) "Anbei"
   3) " birthday"
   4) "1969-10-19"
   5) "city"
   6) "Dongjing"
   ```
   ![](https://support.huaweicloud.com/bestpractice-dcs/public_sys-resources/note_3.0-zh-cn.png)
   也可以根据实际场景中需要的查询方式调整迁移方案。例如把MySQL数据中的其他列转换为hash中的key，把id列转换为field。
   
   
 
