$Id: mysql-plugin.xml 587 2013-12-16 14:00:00Z netkiller
版權聲明
轉載請與作者聯繫,轉載時請務必標明文章原始出處和作者信息及本聲明。
|
|
|
微信掃瞄二維碼進入 Netkiller 微信訂閲號 QQ群:128659835 請註明“讀者” |
2017-06-16: 2013-12-16 13:34:20 +0800 (Thu, 16 May 2013)
你是否想過當資料庫中的數據發生變化的時候出發某種操作?但因數據無法與其他進程通信(傳遞信號)讓你放棄,而改用每隔一段時間查詢一次數據變化的方法?下面的插件可以解決你的問題。
原文出處:http://netkiller.github.io/journal/mysql.plugin.fifo.html
你是否有這樣的需求:
你需要監控訪問網站的IP,當同一個IP地址訪問次數過多需要做出處理,例如拉黑,直接丟進iptables 防火牆規則連中。你的做法只能每個一段時間查詢一次資料庫,並且判斷是否滿足拉黑需求?
你是否需要監控某些數據發生變化,並通知其他程序作出處理。例如新聞內容修改後,需要立即做新頁面靜態化處理,生成新的靜態頁面
你使用資料庫做隊列,例如發送郵件,短信等等。你要通知發送程序對那些手機或者短線發送數據
需要讓資料庫與其他進程通信,傳遞信號
例如,發送短信這個需求,你只要告訴發短信的機器人發送的手機號碼即可,機器人永遠守候那哪裡,只要命令一下立即工作。
監控資料庫變化的需求原理類似,我們需要有一個守護進程等待命令,一旦接到下達命令便立即生成需要的靜態頁面
這裡所提的方案是採用fifo(First In First Out)方案,通過管道相互傳遞信號,使兩個進程協同工作,這樣的效率遠比定時任務高許多。fifo是用於操作系統內部進程間通信,如果跨越操作系統需要使用Socket,還有一個新名詞MQ(Message queue).
這裡只做fifo演示, 將本程序改為Socket方案,或者直接整合成熟的MQ也是分分鐘可以實現。
我開發了幾個 UDF, 共4個 function
創建管道.成功返回true,失敗返回flase.
刪除管道.成功返回true,失敗返回flase.
讀操作.
寫操作 pipename管道名,message消息正文.
有了上面的function後你就可以在begin,commit,rollback 直接穿插使用,實現在事物處理期間做你愛做的事。也可以用在觸發器與EVENT定時任務中。
編譯UDF你需要安裝下面的軟件包
sudo apt-get install pkg-config sudo apt-get install libmysqlclient-dev sudo apt-get install gcc gcc-c++ make automake autoconf
https://github.com/netkiller/mysql-fifo-plugin
編譯udf,最後將so檔案複製到 /usr/lib/mysql/plugin/
git clone https://github.com/netkiller/mysql-image-plugin.git cd mysql-image-plugin gcc -O3 -g -I/usr/include/mysql -I/usr/include -fPIC -lm -lz -shared -o fifo.so fifo.c sudo mv fifo.so /usr/lib/mysql/plugin/
裝載
create function fifo_create returns string soname 'fifo.so'; create function fifo_remove returns string soname 'fifo.so'; create function fifo_read returns string soname 'fifo.so'; create function fifo_write returns string soname 'fifo.so';
卸載
drop function fifo_create; drop function fifo_remove; drop function fifo_read; drop function fifo_write;
插件有很多種用法,這裡僅僅一個例
CREATE TABLE `demo` ( `id` INT(11) NULL DEFAULT NULL, `name` CHAR(10) NULL DEFAULT NULL, `mobile` VARCHAR(50) NULL DEFAULT NULL ) COLLATE='utf8_general_ci' ENGINE=InnoDB; INSERT INTO `demo` (`id`, `name`, `mobile`) VALUES (1, 'neo', '13113668891'), (2, 'jam', '13113668892'), (3, 'leo', '13113668893');
我們假設有一個demo這樣的表,我使用shell寫了一個守護進程用於處理資料庫送過來的數據
#!/bin/bash ######################################## # Homepage: http://netkiller.github.io # Author: neo <netkiller@msn.com> ######################################## NAME=demo PIPE=/tmp/myfifo ######################################## LOGFILE=/tmp/$NAME.log PIDFILE=/tmp/${NAME}.pid ######################################## function start(){ if [ -f "$PIDFILE" ]; then exit 2 fi if [ ! -f "$LOGFILE" ]; then > ${LOGFILE} fi for (( ; ; )) do while read line do NOW=$(date '+%Y-%m-%d %H:%M:%S') echo "[${NOW}] [OK] ${line}" >> ${LOGFILE} done < $PIPE done & echo $! > $PIDFILE } function stop(){ [ -f $PIDFILE ] && kill `cat $PIDFILE` && rm -rf $PIDFILE } case "$1" in start) start ;; stop) stop ;; status) ps ax | grep ${0} | grep -v grep | grep -v status ;; restart) stop start ;; *) echo $"Usage: $0 {start|stop|status|restart}" exit 2 esac exit $?
啟動守護進程
$ ./sms.sh start $ ./sms.sh status 596 pts/5 S 0:00 /bin/bash ./sms.sh start
監控日誌,因為守護進程沒有輸出,完成人戶後寫入日誌。
$ tail -f /tmp/demo.log
開始推送任務
mysql> select fifo_write('/tmp/myfifo',concat(mobile,'\r\n')) from demo; +-------------------------------------------------+ | fifo_write('/tmp/myfifo',concat(mobile,'\r\n')) | +-------------------------------------------------+ | true | | true | | true | +-------------------------------------------------+ 3 rows in set (0.00 sec)
現在看看日誌的變化
$ tail -f /tmp/demo.log [2013-12-16 14:55:48] [OK] 13113668891 [2013-12-16 14:55:48] [OK] 13113668892 [2013-12-16 14:55:48] [OK] 13113668893
我們再將上面的例子使用觸發器進一步優化
CREATE TABLE `demo_sent` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `mobile` VARCHAR(50) NOT NULL, `status` ENUM('true','false') NOT NULL DEFAULT 'false', `ctime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB CREATE DEFINER=`dba`@`%` TRIGGER `demo_after_insert` AFTER INSERT ON `demo` FOR EACH ROW BEGIN insert into demo_sent(mobile,status) select new.mobile,fifo_write('/tmp/myfifo',concat(new.mobile,'')) as status; END
測試
mysql> insert into demo(name,mobile) values('jerry','13322993040'); Query OK, 1 row affected (0.05 sec)
日誌變化
$ tail -f /tmp/demo.log [2013-12-16 14:55:48] [OK] 13113668891 [2013-12-16 14:55:48] [OK] 13113668892 [2013-12-16 14:55:48] [OK] 13113668893 [2013-12-16 14:55:48] [OK] 13322993040
我們可以採用主從資料庫,將任務放在專用的從庫上執行
我們可以創建很多個管道,用於做不同的工作,例如插入一個任務,更新一個任務,發短信一個任務,處理模板與靜態化一個任務等等。