zoukankan      html  css  js  c++  java
  • 【Redis 向Redis中批量导入mysql中的数据(亲自测试)】

    转自:https://blog.csdn.net/kenianni/article/details/84910638 有改动,仅供个人学习

    问题提出:缓存的冷启动问题

    应用系统新版本上线,这时候 redis cluster 集群内存中可能没有数据的,这时候大量请求进去,会导致大量的高并发请求和流量直接打到mysql 中,完蛋,mysql 挂了,redis cluster 集群中也没有数据,这时候整个系统就处于不可用状态;应用系统运行过程中,突然 redis cluster 集群挂了,内存中数据也没有了,就算开启了持久化也无法恢复数据,然后集群在故障中重新启动,这时候全部请求同样进入mysql,mysql 也搞挂了,系统同样出于不可用状态。

    从上面两点看,不管如何,只要redis cluster 集群内存中没有数据,那么大量请求进来,都有可能导致mysql崩溃,从而系统不可以用。

    redis cluster 集群启动,没有任何的缓存数据,可以称之为redis缓存冷启动。

    缓存冷启动,redis cluster启动后,没有任何数据,就直接对外提供服务了,这是mysql 就相当于裸奔状态。解决冷启动的方案是数据预热:

    解决方案思路

    redis 启动后,提前给redis 灌入部分数据,然后再给应用提供服务部分数据指的是根据当天具体的访问情况,进行时时统计出访问频率较高的数据(热数据),因为我们不可能将所有数据写入redis,数据量大,灌入数据时间消耗长,而且也没必要热数据会比较多,这时候我们需要多个服务并行进行读写(并行的分布式缓存预热)完成以上数据预热,然后提供对外服务,这样就不会存在redis 冷启动了,从而减少了大部分数据的 mysql 读压力。

    举例场景:存储游戏玩家的任务数据,游戏服务器启动时将mysql中玩家的数据同步到redis中。

    1 从MySQL中将数据导入到Redis的Hash结构中。当然,最直接的做法就是遍历MySQL数据,一条一条写入到Redis中。这样没什么错,但是速度会非常慢。如果能够想法使得MySQL的查询输出数据直接能够与Redis命令行的输入数据协议相吻合,可以节省很多消耗和缩短时间。

    Mysql数据库名称为:GAME_DB, 表结构举例:

    1 CREATE TABLE TABLE_MISSION (
    2     playerId int(11) unsigned NOT NULL,
    3     missionList varchar(255) NOT NULL,
    4     PRIMARY KEY (playerId)
    5 );

    Redis中的数据结构使用哈希表:

    键KEY为mission, 哈希域为mysql中对应的playerId, 哈希值为mysql中对应的missionList。 数据如下:

    1 [root@iZ23zcsdouzZ ~]# redis-cli
    2 127.0.0.1:6379> hget missions 36598
    3 "{"10001":{"status":1,"progress":0},"10002":{"status":1,"progress":0},"10003":{"status":1,"progress":0},"10004":{"status":1,"progress":0}}"

    快速同步方法:

    新建一个后缀.sql文件:mission.sql内容如下:

     1 SELECT CONCAT(
     2   "*4
    ",
     3   '$', LENGTH(redis_cmd), '
    ',
     4   redis_cmd, '
    ',
     5   '$', LENGTH(redis_key), '
    ',
     6   redis_key, '
    ',
     7   '$', LENGTH(hkey), '
    ',
     8   hkey, '
    ',
     9   '$', LENGTH(hval), '
    ',
    10   hval, '
    '
    11 )
    12 FROM (
    13   SELECT
    14   'HSET' as redis_cmd,
    15   'missions' AS redis_key,
    16   playerId AS hkey,
    17   missionList AS hval
    18   FROM TABLE_MISSION
    19 ) AS t

    保存退出,在命令行执行命令(或写成一个shell脚本):

    1 mysql GAME_DB --skip-column-names --raw < mission.sql | redis-cli --pipe

    上述命令中参数说明:

    1 很重要的mysql参数说明:
    2 --raw: 使mysql不转换字段值中的换行符。
    3 --skip-column-names: 使mysql输出的每行中不包含列名。

    数据库中有7条数据,测试成功输出:

    1 All data transferred. Waiting for the last reply...
    2 Last reply received from server.
    3 errors: 0, replies: 7

    Linux系统终端执行命令后,将mysql数据库GAME_DB的表TABLE_MISSION数据同步到redis中键missions中去。mission.sql文件就是将mysql数据的输出数据格式和redis的输入数据格式协议相匹配,从而大大缩短了同步时间

    经过测试,同样一份数据通过单条取出修改数据格式同步写入到redis消耗的时间为5min, 使用上面的sql文件和shell命令,同步完数据仅耗时3s左右。

    关于以上的补充

    1、mysql配置root用户免密登录:

    执行命令:

    1 mysql GAME_DB --skip-column-names --raw < mission.sql | redis-cli --pipe

    需要使得mysql处于免密码登录的状态,否则会报如下的错:

    1 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

    具体的配置mysql免密的方式有常用的2种:

    【方法1】

     1 cd到root用户家目录下 创建 .my.cnf 的文件后vim进行编辑
     2 普通用户则是/home目录下创建
     3 输入命令
     4 vim .my.cnf
     5 然后在文件中输入下面的命令
     6 [client]
     7 host=localhost
     8 user="root" #如是普通用户输入用户名即可
     9 password="******" #这里填入你的mysql root(普通用户)用户对应的密码
    10 保存退出后 重新启动MySQL数据库即可
    11 systemctl restart mysqld
    12 root用户直接输入 mysql即可登陆mysql数据库
    13 普通用户输入 show mysql

    【方法2】(测试)

     1 进入到mysql数据库的配置文件当中  vim /etc/my.cnf
     2 在[mysqld]的段中加上一句:skip-grant-tables
     3 例如:
     4 [mysqld]
     5 datadir=/var/lib/mysql
     6 socket=/var/lib/mysql/mysql.sock
     7 skip-name-resolve
     8 skip-grant-tables
     9 保存并且退出vim
    10 重新启动mysql数据库即可

    2、可以使用命令而非免密登录的方式执行shell命令:

    1 mysql -h host -uroot -p123456 test --default-character-set=utf8 --skip-column-names --raw < /usr/redis/order.sql | /usr/redis/redis-cli -h host -p 6379 -a 123456 --pipe
    2 
    3 #-h host -uroot -p123456 test 分别为:mysql远程地址,用户名,密码,数据库名
    4 #/usr/redis/order.sql | /usr/redis/redis-cli 分别为sql文件和redis客户端文件目录的地址
    5 #-h host -p 6379 -a 123456  分别为redis远程地址,端口,密码

    或者

    1 mysql -uroot -proot -Dxfdb --default-character-set=utf8 --skip-column-names --raw < mysql_to_redis.sql | redis-cli -h 127.0.0.1 --pipe

    3、编写sql脚本的编码问题:

    如果直接复制上述sql脚本中的内容到linux终端的vim中,可能会报错,如下:

    ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'oSELECT CONCAT(
      "*4
    ",
      '$', LENGTH(redis_cmd), '
    ',
      redis_cmd, '
    ' at line 1
    All data transferred. Waiting for the last reply...
    Last reply received from server.
    errors: 0, replies: 0

    此时,可以先将sql脚本内容复制到文本编辑器中(例如sublime),然后再复制到vim中。

  • 相关阅读:
    20155222 2016-2017-2 《Java程序设计》第8周学习总结
    20155222 2016-2017-2 《Java程序设计》实验一
    20155222 2016-2017-2 《Java程序设计》第7周学习总结
    20155222 2016-2017-2 《Java程序设计》第6周学习总结
    # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
    20155222 2016-2017-2 《Java程序设计》第4周学习总结
    20155222 2016-2017-2 《Java程序设计》第3周学习总结
    # 20155222卢梓杰 2016-2017-2 《Java程序设计》第2周学习总结
    20155222卢梓杰 《Java程序设计》第1周学习总结
    将linux上的Java代码上传到码云
  • 原文地址:https://www.cnblogs.com/xuelisheng/p/10863308.html
Copyright © 2011-2022 走看看