【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\r\n",
 3   '$', LENGTH(redis_cmd), '\r\n',
 4   redis_cmd, '\r\n',
 5   '$', LENGTH(redis_key), '\r\n',
 6   redis_key, '\r\n',
 7   '$', LENGTH(hkey), '\r\n',
 8   hkey, '\r\n',
 9   '$', LENGTH(hval), '\r\n',
10   hval, '\r'
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\r\n",
  '$', LENGTH(redis_cmd), '\r\n',
  redis_cmd, '\r\n' at line 1
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 0

此時,可以先將sql腳本內容復制到文本編輯器中(例如sublime),然后再復制到vim中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM