序文
システムの動作により、データの量がより多く、簡単にMySQLでは、すでに照会のデータストレージ要件を満たすことができないだろう、この時間は、我々はクエリキャッシュ層としてのRedisを紹介なり、熱がRedisのに業務データが保存されます、従来のリレーショナルデータベースサービス機能の拡張、ユーザーが迅速にRedisの共通のデータから直接アプリケーションを介して取得、または対話型アプリケーションでのアクティブなユーザセッションを保存するためのRedisを使用し、大幅にアップグレードし、バックエンドのリレーショナルデータベースの負荷を軽減することができますユーザーエクスペリエンス。
伝統的なコマンドの欠点
従来のRedisのクライアントコマンドを使用すると、大規模なデータインポートのシナリオでは、次のような欠点があります。
Redisのモデルはシングルスレッドであるため、マルチスレッドを迅速にスレッド切り替え時間がかかり、逐次単一の実行コマンドが回避が、データのインポートシーンの大量に、コマンドの結果に応答してサーバによって送信された受信時間がかかるされかかる時間は増幅されます。
インポートデータ1,000,000に必要がある場合は、単にコマンド実行時間という、それは1,000,000 *(T1 + T2)かかります。
コマンドを一つずつ送信することに加えて、当然のことながら、デザインは確かにパイプラインパイプラインモードので、そこに、この問題を検討するのRedis。
しかし、コマンドラインをパイプライン化することはできませんので、我々は、応答数量を受信するために、新たな処理コードを記述する必要があります。しかし、このようなPHP-Redisの拡張としてだけ非常に少ないサポートクライアント側のコードは、非同期をサポートしていません。
パイプラインモードパイプライン、実際には、コマンドのバッチが終了するTCPコネクションの相互作用時間を短縮し、1回の結果を送信します。
原理は、データの順序ことを保証するために、そのFIFO(先入れ先出し)キューを使用することです。
クライアント支持体の小さい部分のみ、ノンブロッキングI / Oは、すべてのクライアントは、スループット最大化するための答えを解決するための効果的な方法することができません。
これらの理由から、RedisのRedisのプロトコル・データ・フォーマットを含んで形成されているデータの膨大な量を導入する好ましい方法は、バッチは、過去に送信されます。
データのインポートのRedisのウォームアップ
NCを使用してデータをインポートするためのコマンド
NCはnetcatを速記で、NC役割は以下のとおりです。
(1)任意のTCP / UDPポートリスナー、モード指定されたポートをリスニングにTCPやUDPサーバとしてパラメータ-l、NCを増加させた後
(2)クライアントがTCPまたはUDPの接続を開始してもよいことNCポートスキャン、
(3)は、マシン間でファイルを転送するには
機械速度ネットワークとの間の(4)
モデルのパイプを使用してデータをインポート
すべてのデータを送信する際のnetcatが本当にエラーをチェックすることができない、知らないのでしかし、リスナーNC使用は、大規模データのインポートを実行するための非常に信頼性の高い方法ではありません。Redisの中にバージョン2.6以降では、Redisの-cliスクリプトは、このモデルは、大規模と設計を実行するために挿入され、パイプのパイプラインモードと呼ばれる新しいモデルをサポートしています。
次のように使うパイプラインモードのコマンドは動作します。
上記のチャートから、あなたがそこにコマンドtxtファイル内にあり、数は回答の数で返す行数コマンドリターンパイプの結果を見ることができ、
エラーは実行中の間違ったコマンドの数を示しています。
合意を学ぶのRedis
次のようにプロトコルの形式は次のとおりです。
* <パラメータの数> \ R&LT \ N- <パラメータ1のバイト数> $ \ R&LT \ N- <dataパラメータ1> \ R&LT \ N- ... $ <パラメータのバイト数N> \ R&LT \ N- <パラメータNデータ> \ rを\ nは
例:
データ型のハッシュを挿入します。
HSETのID BOOK1 book_description1
契約、四つの部分の合計なので、残りは次のように説明されている* 4で始まるに従って、Redisの:
コンテンツ | 長さ | プロトコルコマンド |
---|---|---|
HSET | 4 | $ 4 |
ID | 2 | $ 2 |
BOOK1 | 5 | $ 5 |
book_description1 | 17 | $ 17 |
注:HSETコマンド自体が送信するためのプロトコルなどのパラメータの一つです。
プロトコルデータ構造を構築します:
*4\r\n$4\r\nHSET\r\n$2\r\nid\r\n$5\r\nbook1\r\n$17\r\nbook_description1\r\n 格式化一下: *4\r\n $4\r\n HSET\r\n $2\r\n idvvvv\r\n $5\r\n book1\r\n $17\r\n book_description1\r\n
RESP协议 bulk
Redis客户机使用一种称为RESP (Redis序列化协议)的协议与Redis服务器通信。
redis-cli pipe模式需要和nc命令一样快,并且解决了nc命令不知道何时命令结束的问题。
在发送数据的同时,它同样会去读取响应,尝试去解析。
一旦输入流中没有读取到更多的数据之后,它就会发送一个特殊的20比特的echo命令,标识最后一个命令已经发送完毕
如果在响应结果中匹配到这个相同数据后,说明本次批量发送是成功的。
使用这个技巧,我们不需要解析发送给服务器的协议来了解我们发送了多少命令,只需要解析应答即可。
在解析应答时,redis会对解析的应答进行一个计数,在最后能够告诉用户大量插入会话向服务器传输的命令的数量。也就是上面我们使用pipe模式实际操作的响应结果。
将输入数据源换成mysql
上面的例子中,我们以一个txt文本为输入数据源,使用了pipe模式导入数据。
基于上述协议的学习和理解,我们只需要将mysql中的数据按照既定的协议通过pipe模式导入Redis即可。
实际案例—从Mysql导入百万级数据到Redis
首先造数据
由于环境限制,所以这里没有用真实数据来实现导入,那么我们就先使用一个存储过程来造一百万条数据把。使用存储过程如下:
DELIMITER $$ USE `cb_mon`$$ DROP PROCEDURE IF EXISTS `test_insert`$$ CREATE DEFINER=`root`@`%` PROCEDURE `test_insert`() BEGIN DECLARE i INT DEFAULT 1; WHILE i<= 1000000 DO INSERT INTO t_book(id,number,NAME,descrition) VALUES (i, CONCAT("00000",i) , CONCAT('book',i) , CONCAT('book_description',i)); SET i=i+1; END WHILE ; COMMIT; END$$ DELIMITER ;
调用存储过程:
CALL test_insert();
查看表数据:
按协议构造查询语句
按照上述redis协议,我们使用如下sql来构造协议数据
SELECT CONCAT( "*4\r\n", "$", LENGTH(redis_cmd), "\r\n", redis_cmd, "\r\n", "$", LENGTH(redis_key), "\r\n", redis_key, "\r\n", "$", LENGTH(hkey), "\r\n", hkey, "\r\n", "$", LENGTH(hval), "\r\n", hval, "\r" ) FROM (SELECT "HSET" AS redis_cmd, id AS redis_key, NAME AS hkey, descrition AS hval FROM cb_mon.t_book ) AS t limit 1000000
并将内容保存至redis.sql 文件中。
编写脚本使用pipe模式导入redis
编写shell脚本。由于我在主机上是通过docker安装的redis和mysql,以下脚本供参考:
#!/bin/bash
starttime=`date +'%Y-%m-%d %H:%M:%S'` docker exec -i 899fe01d4dbc mysql --default-character-set=utf8 --skip-column-names --raw < ./redis.sql | docker exec -i 4c90ef506acd redis-cli --pipe endtime=`date +'%Y-%m-%d %H:%M:%S'` start_seconds=$(date --date="$starttime" +%s); end_seconds=$(date --date="$endtime" +%s); echo "脚本执行耗时: "$((end_seconds-start_seconds))"s"
执行截图:
可以看到百万级的数据导入redis,只花费了7秒,效率非常高。
注意事项
如果mysql表特别大,可以考虑分批导入,或者将表拆分,否则在导入过程中可能会发生
lost connection to mysql server during query
由于max_allowed_packed和超时时间限制,查询数据的过程中,可能会造成连接断开,所以在数据表的数据量特别大的时候,需要分页或者将表拆分导入。
总结
この記事では、効率的Redisのを、外出先に移行する方法、百万の順に次のMySQLのデータに焦点を当て、徐々にコースの目標を達成するため、以下の点を総括します
ランが単一のスレッドのRedis、スレッド切り替え時間を消費が回避されるが、遅延の受信に応答して、大規模なデータ送信のために無視することはできません。
NCネットワークのシナリオでは、コマンド、および欠点の存在下でのデータをインポート。
RedisのRESP理解と合意を適用します。
メガMySQLのデータをすぐにインポートする場合をRedisの。
研究や議論を容易にするために、私は、Javaの相互タックル難しく、家族、および他の伝統的な学習の異なる交流を作成しました。このグループには、解決が困難に直面したプロジェクト、プロジェクト内の困難な問題の解決に焦点を当てています。
ときの質問は、彼らがこの大家族に助けを求めることができます。
質問に対する回答を入力するための応答なし[パブリック]:Javaラッパークラス整数型での基本的なデータ?
プロジェクトで発生した問題を経験している場合は、起動することはできません。
百人がアイデアの百種類を持って、他の人はあなたにいくつかのアイデアや意見を与えることができますがあるかもしれません、
あなたが他の人が直面する問題を解決するのに役立つ他の人に喜んでいる場合は同様に、あまりにも、それはあなたのために、運動の一種です。