1. 程式人生 > 其它 >資料庫程序間通訊解決方案

資料庫程序間通訊解決方案

資料庫程序間通訊解決方案

資料庫與其他第三方應用程式程序間通訊解決方案

摘要

你是否想過當資料庫中的資料發生變化的時候出發某種操作?但因資料無法與其他程序通訊(傳遞訊號)讓你放棄,而改用每隔一段時間查詢一次資料變化的方法?下面的外掛可以解決你的問題。

原文出處:http://netkiller.github.io/journal/mysql.plugin.fifo.html


目錄

  • 1. 背景
  • 2. 解決思路
  • 3. Mysql plugin
  • 4. plugin 的開發與使用
  • 5. 外掛如何使用
  • 6. 部署相關問題

1. 背景

你是否有這樣的需求:

你需要監控訪問網站的IP,當同一個IP地址訪問次數過多需要做出處理,例如拉黑,直接丟進iptables 防火牆規則連中。你的做法只能每個一段時間查詢一次資料庫,並且判斷是否滿足拉黑需求?

你是否需要監控某些資料發生變化,並通知其他程式作出處理。例如新聞內容修改後,需要立即做新頁面靜態化處理,生成新的靜態頁面

你使用資料庫做佇列,例如傳送郵件,簡訊等等。你要通知傳送程式對那些手機或者短線傳送資料

2. 解決思路

需要讓資料庫與其他程序通訊,傳遞訊號

例如,傳送簡訊這個需求,你只要告訴發簡訊的機器人傳送的手機號碼即可,機器人永遠守候那哪裡,只要命令一下立即工作。

監控資料庫變化的需求原理類似,我們需要有一個守護程序等待命令,一旦接到下達命令便立即生成需要的靜態頁面

這裡所提的方案是採用fifo(First In First Out)方案,通過管道相互傳遞訊號,使兩個程序協同工作,這樣的效率遠比定時任務高許多。fifo是用於作業系統內部程序間通訊,如果跨越作業系統需要使用Socket,還有一個新名詞MQ(Message queue).

這裡只做fifo演示, 將本程式改為Socket方案,或者直接整合成熟的MQ也是分分鐘可以實現。

3. Mysql plugin

我開發了幾個 UDF, 共4個 function

UDF

  • fifo_create(pipename)
  • 建立管道.成功返回true,失敗返回flase.
  • fifo_remove(pipename)
  • 刪除管道.成功返回true,失敗返回flase.
  • fifo_read(pipename)
  • 讀操作.
  • fifo_write(pipename,message)
  • 寫操作 pipename管道名,message訊息正文.

有了上面的function後你就可以在begin,commit,rollback 直接穿插使用,實現在事物處理期間做你愛做的事。也可以用在觸發器與EVENT定時任務中。

4. plugin 的開發與使用

編譯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;		

5. 外掛如何使用

外掛有很多種用法,這裡僅僅一個例

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 <[email protected]>
########################################
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,'rn')) from demo;
+-------------------------------------------------+
| fifo_write('/tmp/myfifo',concat(mobile,'rn')) |
+-------------------------------------------------+
| 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		

6. 部署相關問題

我們可以採用主從資料庫,將任務放在專用的從庫上執行

我們可以建立很多個管道,用於做不同的工作,例如插入一個任務,更新一個任務,發簡訊一個任務,處理模板與靜態化一個任務等等