標籤:快取資料庫 redis mysql gearman
環境:
centos6.5
mysql5.6
gearman簡介:
Gearman是一個支援分布式的任務分發架構。設計簡潔,獲得了非常廣泛的支援。一個典型的Gearman應用程式套件括以下這些部分:
Gearman Job Server:Gearman核心程式,以守護進程形式運行在後台
Gearman Client:可以理解為任務的收件員,比如我要在後台執行一個發送郵件的任務,可以在程式中調用一個Gearman Client並傳入郵件的資訊,然後就可以將執行結果立即展示給使用者,而任務本身會慢慢在後台運行。
Gearman Worker:任務的真正執行者,一般需要自己編寫具體邏輯並通過守護進程方式運行,Gearman Worker接收到Gearman Client傳遞的任務內容後,會按順序處理。
設計思路:
首先利用mysql UDF(通過了lib_mysqludf_json和gearman-mysql-udf的組合實現)在mysql中的資料發生改變時觸動觸發器將資料傳入Gearman中,這時的mysql相當於Gearman的clinet。然後運行自己編寫的php程式作為worker,將Gearman中的資料傳到Redis中去,這時的Redis相當於是Gearman的consumer。
1、安裝gearman
實驗中的系統yum源在centos6.5內建的網路yum源的基礎上,增加了epel的源,EPEL (Extra Packages for Enterprise Linux,企業版Linux的額外軟體包) 是Fedora小組維護的一個軟體倉庫項目,為RHEL/CentOS提供他們預設不提供的軟體包。使用這個源可以免去很多麻煩,省去源碼編譯的麻煩,需要注意的是,不論是使用centos內建的網路yum源還是epel擴充源,都需要你的IP能夠訪問到公網。
安裝gearman、php、php的gearman擴充、nc工具
yum install -y php-pecl-gearman libgearman libgearman-devel gearmand nc
啟動gearman服務
/etc/init.d/gearmand start
驗證gearman是否成功啟動,如果返回的結果中有4730連接埠,那麼表示服務已經正常啟動了
[[email protected] ~]# netstat -alnutp |grep gearman
2、類比Gearman的工作原理:
使用下列命令查看Gearman的隊列
watch -n 1 "(echo status; sleep 0.1) | nc 127.0.0.1 4730"
結果如下
writeLog 0 0 0
四列含義:1-任務名稱;2-等待隊列任務數;3-運行中的任務數;4-正在啟動並執行worker進程數;
編譯一段php代碼類比Gearman的Client:client.php
<?php $client = new GearmanClient(); $client->addServer(); $client->doBackground(‘writeLog‘, ‘Log content‘); echo ‘檔案已經在後台操作‘; echo "\n";
執行client.php
php client.php
這時,再次查看Gearman的隊列,發現等待隊列中有一個任務
writeLog 1 0 0
編寫一段php代碼類比Gearman的Worker:worker.php
該worker的作用是將用戶端傳遞給Gearman的字串‘Log content‘寫入到目前的目錄下的gearman.log檔案中
<?php $worker = new GearmanWorker(); $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); }
以nohup的方式後台啟動worker.php
nohup php worker.php &
再次查看Gearman的隊列,發現等待的任務變成0,worker進程變成了1,gearman.log有了內容
writeLog 0 0 1
[[email protected] ~]# cat gearman.log Log content
3、安裝mysql-server、mysql、php-mysql(php串連mysql的驅動,非必須,這裡是為了稍後用程式比較從Redis和Mysql中分別讀取資料的效率)。實驗中,由於我的機子上之前已將安裝了mysql5.6,所以就直接使用mysql5.6做實驗了。當然也可以使用yum開安裝mysql,可能安裝的mysql版本不是5.6,但是完全沒有關係。
安裝mysql相關軟體
yum install -y mysql-server mysql php-mysql
啟動mysql
/etc/init.d/mysql start
4、安裝lib_mysqludf_json
wget https://github.com/mysqludf/lib_mysqludf_json/archive/master.zipmv master master.zipunzip master.zipcd lib_mysqludf_json-masterrm -rf lib_mysqludf_json.so gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
這時重新編譯產生了lib_mysqludf_json.so,然後需要把lib_mysqludf_json.so拷貝到mysql的外掛程式目錄下,查看mysql的外掛程式目錄:
[[email protected] ~]# mysql -u root -pupbjsxt --execute="show variables like ‘%plugin%‘;" +---------------+--------------------------+| Variable_name | Value |+---------------+--------------------------+| plugin_dir | /usr/lib64/mysql/plugin/ |+---------------+--------------------------+
[[email protected] lib_mysqludf_json-master]# cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/
5、安裝gearman-mysql-udf
wget https://launchpad.net/gearman-mysql-udf/trunk/0.6/+download/gearman-mysql-udf-0.6.tar.gz tar xf gearman-mysql-udf-0.6.tar.gz -C ./cd gearman-mysql-udf-0.6./configure --with-mysql=/usr/bin/mysql_config --libdir=/usr/lib64/mysql/plugin/make && make install
該外掛程式直接安裝到了mysql的外掛程式目錄下。
6、連入mysql,建立對應的function、trigger及設定gearman server資訊
[[email protected] ~]# mysql -u root -p****** mysql> CREATE FUNCTION json_object RETURNS STRING SONAME ‘lib_mysqludf_json.so‘;mysql> CREATE FUNCTION gman_do_background RETURNS STRING SONAME ‘libgearman_mysql_udf.so‘;mysql> CREATE FUNCTION gman_servers_set RETURNS STRING SONAME ‘libgearman_mysql_udf.so‘## 為javashop中的test表建立觸發器mysql> use javashop;mysql> describe test;+-------+----------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+----------+------+-----+---------+-------+| id | int(11) | YES | | NULL | || name | char(20) | YES | | NULL | |+-------+----------+------+-----+---------+-------+2 rows in set (0.00 sec)mysql> source trigger.sql## 設定gearman server資訊mysql>SELECT gman_servers_set(‘127.0.0.1:4730‘);
trigger.sql指令檔內容如下
DELIMITER $$CREATE TRIGGER datatoredis AFTER UPDATE ON test FOR EACH ROW BEGIN SET @ret=gman_do_background(‘syncToRedis‘, json_object(NEW.id as `id`, NEW.name as `name`)); END$$DELIMITER ;
7、在mysql中更新一條資料,然後查看gearman的隊列
mysql> update test set name=‘redis‘ where id=10;Query OK, 1 row affected (0.03 sec)Rows matched: 1 Changed: 1 Warnings: 0
writeLog 0 0 1syncToRedis 1 0 0
可見mysql觸發器已經成功的將資料傳入到gearman中了。
8、安裝redis、php-pecl-redis(php串連redis的驅動)
yum install php-pecl-redis redis -y
啟動redis
/etc/init.d/redis start
登入redis用戶端,查看當前記憶體中的資料
[[email protected] ~]# redis-cli redis 127.0.0.1:6379> keys *(empty list or set)
這時,redis中並沒有資料。
9、編寫一個worker程式,負責將gearman中的資料傳入到redis中去:redis_worker.php
<?php $worker = new GearmanWorker(); $worker->addServer(); $worker->addFunction(‘syncToRedis‘, ‘syncToRedis‘); $redis = new Redis(); $redis->connect(‘127.0.0.1‘); while($worker->work()); function syncToRedis($job) { global $redis; $workString = $job->workload(); $work = json_decode($workString); if(!isset($work->id)){ return false; } $redis->set($work->id, $workString); }
10、以nohup的方式後台運行redis_worker.php
nohup php redis_worker.php &
這時,再查看gearman的隊列
writeLog 0 0 1syncToRedis 0 0 1
發現syncToRedis任務之前等待的任務數變為了0,正在啟動並執行worker進程數變為了1。
檢查redis中是否緩衝了資料
[[email protected] ~]# redis-cli redis 127.0.0.1:6379> keys *1) "10"redis 127.0.0.1:6379> get 10"{\"id\":10,\"name\":\"redis\"}"
發現redis中已經成功的緩衝了mysql中更新的資料,至此功能實現。
11、從redis中讀取資料和從mysql中讀取資料效能比較
編寫php代碼,從redis中讀取資料:php_redis.php
<?php $stime=microtime(true); //擷取程式開始執行的時間 $redis = new Redis(); $redis->connect(‘127.0.0.1‘); echo $redis->get(‘10‘); echo "\n"; $redis->close(); $etime=microtime(true);//擷取程式執行結束的時間 $total=$etime-$stime; //計算差值 echo "$total".‘秒‘; echo "\n";?>
編寫php代碼,從mysql中讀取資料:php_mysql.php
<?php $stime=microtime(true); //擷取程式開始執行的時間 $con = mysql_connect("127.0.0.1","root","******"); $r2 = mysql_select_db("javashop"); $result = mysql_query("SELECT * FROM test limit 1"); while ($row = mysql_fetch_array($result)) { echo $row[‘id‘] . " --> " . $row[‘name‘]; echo "\n"; } mysql_close($con); $etime=microtime(true);//擷取程式執行結束的時間 $total=$etime-$stime; //計算差值 echo "$total".‘秒‘; echo "\n"?>
分別運行兩個php程式
[[email protected] ~]# php php_redis.php {"id":10,"name":"redis"}0.00059199333190918秒[[email protected] ~]# php php_mysql.php 10 --> redis0.0043718814849854秒[[email protected] ~]# bc <<< 0.0043718814849854/0.000591993331909187
通過對一條記錄的查詢,可以發現,從mysql中擷取資料的時間長度是redis中擷取資料時間長度的7倍,可見度能的提升幾乎達一個數量級。
注意點:
親測印證了mysql在重啟後會丟失之前設定的gearman server的資訊,解決辦法如下:
在mysql的datadir目錄下建立init_file.sql檔案,內容為gearman server的資訊的設定
echo "SELECT gman_servers_set(‘127.0.0.1:4730‘);" > /var/lib/mysql/init_file.sql
然後在mysql的設定檔的[mysqld]項中添加如下內容
init-file=/var/lib/mysql/init_file.sql
然後重啟mysql,更新一條記錄再試試看!
參考:http://avnpc.com/pages/mysql-replication-to-redis-by-gearman
PS:完成了第一篇部落格,希望大家多多指教,祝生活愉快!
本文出自 “不逼自己就不自知有多牛逼” 部落格,請務必保留此出處http://quenlang.blog.51cto.com/4813803/1568567
利用gearman實現redis緩衝mysql