對於變化頻率很是快的數據來講,若是還選擇傳統的靜態緩存方式(Memocached、File System等)展現數據,可能在緩存的存取上會有很大的開銷,並不能很好的知足須要,而Redis這樣基於內存的NoSQL數據庫,就很是適合擔任實時數據的容器。
可是每每咱們又有數據可靠性的需求,採用MySQL做爲數據存儲,不會由於內存問題而引發數據丟失,同時也能夠利用關係數據庫的特性實現不少功能。
因此就會很天然的想到是否能夠採用MySQL做爲數據存儲引擎,Redis則做爲Cache。而這種需求目前尚未看到有特別成熟的解決方案或工具,所以本文將嘗試採用Gearman+PHP+MySQL UDF的組合異步實現MySQL到Redis的數據複製。
MySQL到Redis數據複製方案
不管MySQL仍是Redis,自身都帶有數據同步的機制,像比較經常使用的MySQL的Master/Slave模式,就是由Slave端分析Master的binlog來實現的,這樣的數據複製其實仍是一個異步過程,只不過當服務器都在同一內網時,異步的延遲幾乎能夠忽略。
那麼理論上咱們也能夠用一樣方式,分析MySQL的binlog文件並將數據插入Redis。可是這須要對binlog文件以及MySQL有很是深刻的理解,同時因爲binlog存在Statement/Row/Mixedlevel多種形式,分析binlog實現同步的工做量是很是大的。
所以這裏選擇了一種開發成本更加低廉的方式,借用已經比較成熟的MySQL UDF,將MySQL數據首先放入Gearman中,而後經過一個本身編寫的PHP Gearman Worker,將數據同步到Redis。比分析binlog的方式增長了很多流程,可是實現成本更低,更容易操做。
Gearman的安裝與使用
Gearman是一個支持分佈式的任務分發框架。設計簡潔,得到了很是普遍的支持。一個典型的Gearman應用包括如下這些部分:php
之前曾經介紹過相似的後臺任務處理項目Resque。二者的設計其實很是接近,簡單能夠類比爲:mysql
這裏之因此選擇Gearman而不是Resque是由於Gearman提供了比較好用的MySQL UDF,工做量更小。
安裝Gearman及PHP Gearman擴展
如下均以Ubuntu12.04爲例。linux
apt-get install gearman gearman-server libgearman-dev
檢查Gearman的運行情況:git
/etc/init.d/gearman-job-server status * gearmand is running
說明Gearman已經安裝成功。
PHP的Gearman擴展能夠經過pecl直接安裝github
pecl install gearman
echo "extension=gearman.so">/etc/php5/conf.d/gearman.ini service php5-fpm restart
可是實測發現ubuntu默認安裝的gearman版本太低,直接運行pecl install gearman會報錯redis
configure: error: libgearman version 1.1.0or later required
所以Gearman + PHP擴展建議經過編譯方式安裝,這裏爲了簡單說明,選擇安裝舊版本擴展:sql
pecl install gearman-1.0.3
Gearman + PHP實例
爲了更容易理解後文Gearman的運行流程,這裏不妨從一個最簡單的Gearman實例來講明,好比咱們要進行一個文件處理的操做,首先編寫一個Gearman Client並命名爲client.php:數據庫
<?php $client =newGearmanClient(); $client->addServer(); $client->doBackground('writeLog','Log content'); echo '文件已經在後臺操做';
運行這個文件,至關於模擬用戶請求一個Web頁面後,將處理結束的信息返回用戶:json
php client.php
查看一下Gearman的情況:ubuntu
(echo status ; sleep 0.1)| netcat127.0.0.14730
能夠看到輸出爲
writeLog 100.
說明咱們已經在Gearman中創建了一個名爲writeLog的任務,而且有1個任務在隊列等待中。
而上面的4列分別表明當前的Gearman的運行狀態:
可使用watch進行實時監控:
watch -n 1"(echo status; sleep 0.1) | nc 127.0.0.1 4730"
而後咱們須要編寫一個Gearman Worker命名爲worker.php:
<?php $worker =newGearmanWorker(); $worker->addServer(); $worker->addFunction('writeLog','writeLog');while($worker->work());function writeLog($job){ $log = $job->workload();file_put_contents(__DIR__ .'/gearman.log', $log ."\n", FILE_APPEND | LOCK_EX);}
Worker使用一個while死循環實現守護進程,運行
php worker.php
能夠看到Gearman狀態變爲:
writeLog 001
同時查看同目錄下gearman.log,內容應爲從Client傳入的值Log content
。
經過MySQL UDF + Trigger同步數據到Gearman
MySQL要實現與外部程序互通的最好方式仍是經過MySQL UDF(MySQL user defined functions)來實現。爲了讓MySQL能將數據傳入Gearman,這裏使用了lib_mysqludf_json和gearman-mysql-udf的組合。
安裝lib_mysqludf_json
使用lib_mysqludf_json的緣由是由於Gearman只接受字符串做爲入口參數,能夠經過lib_mysqludf_json將MySQL中的數據編碼爲JSON字符串
apt-get install libmysqlclient-dev wget https://github.com/mysqludf/lib_mysqludf_json/archive/master.zip unzip master.zip cd lib_mysqludf_json-master/ rm lib_mysqludf_json.so gcc $(mysql_config --cflags)-shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
能夠看到從新編譯生成了 lib_mysqludf_json.so 文件,此時須要查看MySQL的插件安裝路徑:
mysql -u root -pPASSWORD --execute="show variables like '%plugin%';"+---------------+------------------------+|Variable_name|Value|+---------------+------------------------+| plugin_dir |/usr/lib/mysql/plugin/|+---------------+------------------------+
而後將 lib_mysqludf_json.so 文件複製到對應位置:
cp lib_mysqludf_json.so /usr/lib/mysql/plugin/
最後登入MySQL運行語句註冊UDF函數:
CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';
安裝gearman-mysql-udf
方法幾乎同樣:
apt-get install libgearman-dev wget https://launchpad.net/gearman-mysql-udf/trunk/0.6/+download/gearman-mysql-udf-0.6.tar.gz tar -xzf gearman-mysql-udf-0.6.tar.gz cd gearman-mysql-udf-0.6./configure --with-mysql=/usr/bin/mysql_config --libdir=/usr/lib/mysql/plugin/ make && make install
登入MySQL運行語句註冊UDF函數:
CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so'; CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';
最後指定Gearman服務器的信息:
SELECT gman_servers_set('127.0.0.1:4730');
經過MySQL觸發器實現數據同步
最終同步哪些數據,同步的條件,仍是須要根據實際狀況決定,好比我但願將數據表data的數據在每次更新時同步,那麼編寫Trigger以下:
DELIMITER $$
CREATE TRIGGER datatoredis AFTER UPDATE ON data
FOR EACH ROW BEGIN SET @ret=gman_do_background('syncToRedis', json_object(NEW.id as`id`, NEW.volume as`volume`));END$$ DELIMITER ;
嘗試在數據庫中更新一條數據查看Gearman是否生效。
Gearman PHP Worker將MySQL數據異步複製到Redis
Redis做爲時下當熱的NoSQL緩存解決方案無需過多介紹,其安裝及使用也很是簡單:
apt-get install redis-server pecl install redis echo "extension=redis.so">/etc/php5/conf.d/redis.ini
而後編寫一個Gearman Worker:redis_worker.php
#!/usr/bin/env php<? $worker =newGearmanWorker(); $worker->addServer(); $worker->addFunction('syncToRedis','syncToRedis'); $redis =newRedis(); $redis->connect('127.0.0.1',6379);while($worker->work());function syncToRedis($job){global $redis; $workString = $job->workload(); $work = json_decode($workString);if(!isset($work->id)){returnfalse;} $redis->set($work->id, $workString);}
最後須要將Worker在後臺運行:
nohup php redis_worker.php &
經過這種方式將MySQL數據複製到Redis,經測試單Worker基本能夠瞬時完成。
Ubuntu 14.04下Redis安裝及簡單測試 http://www.linuxidc.com/Linux/2014-05/101544.htm
Redis集羣明細文檔 http://www.linuxidc.com/Linux/2013-09/90118.htm
Ubuntu 12.10下安裝Redis(圖文詳解)+ Jedis鏈接Redis http://www.linuxidc.com/Linux/2013-06/85816.htm
Redis系列-安裝部署維護篇 http://www.linuxidc.com/Linux/2012-12/75627.htm
CentOS 6.3安裝Redis http://www.linuxidc.com/Linux/2012-12/75314.htm
Redis安裝部署學習筆記 http://www.linuxidc.com/Linux/2014-07/104306.htm
Redis配置文件redis.conf 詳解 http://www.linuxidc.com/Linux/2013-11/92524.htm
Redis 的詳細介紹:請點這裏
Redis 的下載地址:請點這裏
from:http://avnpc.com/pages/mysql-replication-to-redis-by-gearman%20