从mysql抽取数据传入redis
2021-12-25 本文已影响0人
随风遣入夜
场景
- 有一点需要说明,虽然文章题目是:从mysql抽取数据传入redis,但是内容绝不仅限于此
- 需要将大批量数据快速上传至redis,想一想我们有几百万数据待上传到redis,这时候是不是需要一种高效稳定的方式呢?
- 我们首先需要具备什么样的水平,才能做这件事情?
回答
- 问题回答:
- 用程序一条条传
- 采用redis lua脚本传
- 制作出AOF文件
- 其他我不知道的,待补充,有兴趣评论区告诉我
- 问题回答:
- 了解redis,知道redis数据类型,安装过redis,知道redis-server,redis-cli
- 会一些sql查询语句,会用sql拼接字符
- 一些自学能力
本文的流程
- 了解应用场景
- 了解本文流程
- 学习mysql抽取数据传入redis的具体操作
- 深化系统学习相关知识
准备工作
- 一台centos,安装了mysql,redis的主机
- 建立一个test库,再建立一个user表,加上id,name,cardid,code字段,并随便填入点值进去,做个两三条记录
编写仿AOF文件内容的sql脚本
- 开始写,命名为userjson.sql
SELECT CONCAT(
"*3\r\n",
'$', LENGTH(redis_cmd),'\r\n',redis_cmd,'\r\n',
'$', LENGTH(redis_key),'\r\n',redis_key,'\r\n',
'$', LENGTH(hval1),'\r\n',hval1,'\r'
)
FROM (
SELECT
'SET' as redis_cmd,
CONCAT('user:',id) as redis_key,
CONCAT(
'{"id":"',a.id,'"',
',"name":"',a.name,'"',
',"cardId":"',a.cardId,'"',
',"code":"',a.code,'"}'
) as hval1
FROM user a
) AS t
# 解释下这里的重点
# 1. [*3]代表中的[*]array,3的是[$]的数量,每个[$]代表一个基础操作位的起始
# 2. [\r\n]代表一个分隔符,一个结束语标识;RESP协议中的分隔符为在Linux下是\r\n,而在Windows下则为\n
# 3. 为什么要将sql脚本写成这样的,那是因为,我想把它拼成json字符串,前端或者后端拿到后,就能序列化出来,关键是key带了数据库的主键,用起来速度快啊
# 4. 我们会达到什么样的效果(不包含括号)
[rediskey](user:111)[redisvalue]({"id":"111","name":"小明","cardId":"GTF001","code":"001"})
[rediskey](user:222)[redisvalue]({"id":"222","name":"小花","cardId":"GTF002","code":"002"})
重点来了,将脚本上传至服务器合适的文件夹下,准备命令进行执行
mysql -uroot -p数据库密码 -h 127.0.0.1 数据库名 --default-character-set=utf8 --skip-column-names --raw < userjson.sql | /usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a redis库密码 -n redis库名 --pipe
# 第一部分mysql部分
# mysql -uroot -p数据库密码 -h 127.0.0.1 数据库名 这个就是命令行连接mysql数据库的命令
# --default-character-set=utf8 默认字符
# --skip-column-names --raw 不输出列名
# < userjson.sql 执行脚本
# 第二部分Linux管道符
# | 把一个程序的结果交给另一个来处理 (不要忽视这个,特别重要)
# 第三部分redis-cli命令
# /usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a redis库密码 -n redis库名 常规用redis-cli连接redis-server的命令
# --pipe redis-cli管道操作,也是管道
# 最后合起来, 将mysql的执行结果 交给 redis-cli 进行pipe操作,即从mysql抽取数据传输至redis数据库
一般情况下,不会出现太大问题,请尽量用centos做实验,windows问题太多不适合.
根据我的实操结果,大概68w条的数据,约12秒内即可完成存储,具体因数据宽度和记录条数影响
深化学习
- AOF文件
- pipe操作
- RESP协议
AOF文件说明
- AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。
- Redis 还可以同时使用 AOF 持久化和 RDB 持久化。 在这种情况下, 当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。
pipe操作(Pipeline)
- pipeline是Redis的一个提高吞吐量的机制,适用于多key读写场景,比如同时读取多个key的value,或者更新多个key的value;即一个批处理。
# 参考资料 https://zhuanlan.zhihu.com/p/72867786
RESP协议说明
RESP协议是在Redis 1.2中引入的,但它成为了与Redis 2.0中的Redis服务器通信的标准方式。这是所有Redis客户端都要遵循的协议,我们甚至可以基于此协议,开发实现自己的Redis客户端。
RESP实际上是一个支持以下数据类型的序列化协议:简单字符串,错误类型,整数,批量字符串和数组。
RESP在Redis中用作请求-响应协议的方式如下:
客户端将命令作为Bulk Strings的RESP数组发送到Redis服务器。
服务器根据命令实现回复一种RESP类型。
在RESP中,某些数据的类型取决于第一个字节:
“+”代表简单字符串Simple Strings
“+”代表错误类型
“:”代表整数
$代表Bulk Strings
“*”代表数组
此外,RESP能够使用稍后指定的Bulk Strings或Array的特殊变体来表示Null值。
在RESP中,协议的不同部分始终以“\r\n”(CRLF)结束。
# 参考资料 https://zhuanlan.zhihu.com/p/101564435
我们思考一个问题:为什么redis-cli 能通过pipe传输方式 将仿AOF的形式的数据存储至redis-server呢?
答: redis独有的RESP协议,AOF文件中的*$这些语法规则都是RESP协议中约定的;
结论:redis-cli 能通过pipe传输方式 将仿AOF文件格式的数据通过RESP协议存储至redis-server