数据库进程间通信解决方案 数据库进程间通信解决方案 1. 背景 2. 解决思路 3. Mysql plugin 4. plugin 的开发与使用 5. 插件如何使用 6. 部署相关问题
<h3> Mr. Neo Chen (netkiller), 陈景峰(BG7NYT) </h3>
中国广东省深圳市龙华新区民治街道溪山美地 518131 +86 13113668890 +86 755 29812080 <netkiller@msn.com>
$Id: mysql-plugin.xml 587 2013-12-16 14:00:00Z netkiller $
版权 © 2011, 2012, 2013, 2014 http://netkiller.github.io
<strong>版权声明</strong>
转载请与作者联系,转载时请务必标明文章原始出处和作者信息及本声明。
<table style="border:0px;">
<tbody>
<tr>
<td> <a href="http://creativecommons.org/licenses/by/3.0/" target="_top" rel="nofollow">
<table style="border:0px;width:180px;">
<tbody>
<tr>
<td> <img src="http://static.oschina.net/uploads/img/201405/19110303_lWwI.png" width="180" /> </td>
</tr>
</tbody>
</table> </a> </td>
<td>
<table style="border:0px;">
<tbody>
<tr>
<td> 文档出处: </td>
</tr>
<tr>
<td> <a href="http://netkiller.github.io/" target="_top" rel="nofollow">http://netkiller.github.io</a> </td>
</tr>
<tr>
<td> <a href="http://netkiller.sourceforge.net/" target="_top" rel="nofollow">http://netkiller.sourceforge.net</a> </td>
</tr>
</tbody>
</table> </td>
</tr>
</tbody>
</table>
$Date: 2013-12-16 13:34:20 +0800 (Thu, 16 May 2013) $
摘要
你是否想过当数据库中的数据发生变化的时候出发某种操作?但因数据无法与其他进程通信(传递信号)让你放弃,而改用每隔一段时间查询一次数据变化的方法?下面的插件可以解决你的问题。
原文出处:<a href="http://netkiller.github.io/journal/mysql.plugin.fifo.html" target="_top" rel="nofollow">http://netkiller.github.io/journal/mysql.plugin.fifo.html</a>
我的系列文档
<table style="border:0px;">
<tbody>
<tr>
<td> <a href="http://netkiller.github.io/architect/index.html" target="_top" rel="nofollow">Netkiller Architect 手札</a> </td>
<td> <a href="http://netkiller.github.io/developer/index.html" target="_top" rel="nofollow">Netkiller Developer 手札</a> </td>
<td> <a href="http://netkiller.github.io/php/index.html" target="_top" rel="nofollow">Netkiller PHP 手札</a> </td>
<td> <a href="http://netkiller.github.io/python/index.html" target="_top" rel="nofollow">Netkiller Python 手札</a> </td>
<td> <a href="http://netkiller.github.io/testing/index.html" target="_top" rel="nofollow">Netkiller Testing 手札</a> </td>
<td> <a href="http://netkiller.github.io/cryptography/index.html" target="_top" rel="nofollow">Netkiller Cryptography 手札</a> </td>
</tr>
<tr>
<td> <a href="http://netkiller.github.io/linux/index.html" target="_top" rel="nofollow">Netkiller Linux 手札</a> </td>
<td> <a href="http://netkiller.github.io/debian/index.html" target="_top" rel="nofollow">Netkiller Debian 手札</a> </td>
<td> <a href="http://netkiller.github.io/centos/index.html" target="_top" rel="nofollow">Netkiller CentOS 手札</a> </td>
<td> <a href="http://netkiller.github.io/freebsd/index.html" target="_top" rel="nofollow">Netkiller FreeBSD 手札</a> </td>
<td> <a href="http://netkiller.github.io/shell/index.html" target="_top" rel="nofollow">Netkiller Shell 手札</a> </td>
<td> <a href="http://netkiller.github.io/security/index.html" target="_top" rel="nofollow">Netkiller Security 手札</a> </td>
</tr>
<tr>
<td> <a href="http://netkiller.github.io/www/index.html" target="_top" rel="nofollow">Netkiller Web 手札</a> </td>
<td> <a href="http://netkiller.github.io/monitoring/index.html" target="_top" rel="nofollow">Netkiller Monitoring 手札</a> </td>
<td> <a href="http://netkiller.github.io/storage/index.html" target="_top" rel="nofollow">Netkiller Storage 手札</a> </td>
<td> <a href="http://netkiller.github.io/mail/index.html" target="_top" rel="nofollow">Netkiller Mail 手札</a> </td>
<td> <a href="http://netkiller.github.io/docbook/index.html" target="_top" rel="nofollow">Netkiller Docbook 手札</a> </td>
<td> <a href="http://netkiller.github.io/version/index.html" target="_top" rel="nofollow">Netkiller Version 手札</a> </td>
</tr>
<tr>
<td> <a href="http://netkiller.github.io/database/index.html" target="_top" rel="nofollow">Netkiller Database 手札</a> </td>
<td> <a href="http://netkiller.github.io/postgresql/index.html" target="_top" rel="nofollow">Netkiller PostgreSQL 手札</a> </td>
<td> <a href="http://netkiller.github.io/mysql/index.html" target="_top" rel="nofollow">Netkiller MySQL 手札</a> </td>
<td> <a href="http://netkiller.github.io/nosql/index.html" target="_top" rel="nofollow">Netkiller NoSQL 手札</a> </td>
<td> <a href="http://netkiller.github.io/ldap/index.html" target="_top" rel="nofollow">Netkiller LDAP 手札</a> </td>
<td> <a href="http://netkiller.github.io/network/index.html" target="_top" rel="nofollow">Netkiller Network 手札</a> </td>
</tr>
<tr>
<td> <a href="http://netkiller.github.io/cisco/index.html" target="_top" rel="nofollow">Netkiller Cisco IOS 手札</a> </td>
<td> <a href="http://netkiller.github.io/h3c/index.html" target="_top" rel="nofollow">Netkiller H3C 手札</a> </td>
<td> <a href="http://netkiller.github.io/multimedia/index.html" target="_top" rel="nofollow">Netkiller Multimedia 手札</a> </td>
<td> <a href="http://netkiller.github.io/perl/index.html" target="_top" rel="nofollow">Netkiller Perl 手札</a> </td>
<td> <a href="http://netkiller.github.io/radio/index.html" target="_top" rel="nofollow">Netkiller Amateur Radio 手札</a> </td>
<td> </td>
</tr>
</tbody>
</table>
目录
你是否有这样的需求:
你需要监控访问网站的IP,当同一个IP地址访问次数过多需要做出处理,例如拉黑,直接丢进iptables 防火墙规则连中。你的做法只能每个一段时间查询一次数据库,并且判断是否满足拉黑需求?
你是否需要监控某些数据发生变化,并通知其他程序作出处理。例如新闻内容修改后,需要立即做新页面静态化处理,生成新的静态页面
你使用数据库做队列,例如发送邮件,短信等等。你要通知发送程序对那些手机或者短线发送数据
需要让数据库与其他进程通信,传递信号
例如,发送短信这个需求,你只要告诉发短信的机器人发送的手机号码即可,机器人永远守候那哪里,只要命令一下立即工作。
监控数据库变化的需求原理类似,我们需要有一个守护进程等待命令,一旦接到下达命令便立即生成需要的静态页面
这里所提的方案是采用fifo(First In First Out)方案,通过管道相互传递信号,使两个进程协同工作,这样的效率远比定时任务高许多。fifo是用于操作系统内部进程间通信,如果跨越操作系统需要使用Socket,还有一个新名词MQ(Message queue).
这里只做fifo演示, 将本程序改为Socket方案,或者直接集成成熟的MQ也是分分钟可以实现。
我开发了几个 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定时任务中。
编译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-plugingit 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 TABLEdemo
(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');
#!/bin/bash ########################################
######################################## 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
我们可以采用主从数据库,将任务放在专用的从库上执行
我们可以创建很多个管道,用于做不同的工作,例如插入一个任务,更新一个任务,发短信一个任务,处理模板与静态化一个任务等等。
不明觉厉啊######只是针对了mysql的插件开发解决,标题挂的是数据库会不会有点大了######请教下,这个思路能不能推广应用到其他几个主流数据库?如果可以,这标题就不仅不大,而且还很准确。######呵呵,不好意思,我正在写自己的数据库,所以你这个文我很喜欢。######好的,我抽时间学习研究下你这个。正好我很可能会用上。谢谢。######目前来说,很多数据库都很开放,都提供扩展开发,例如mysql开发一个插件,甚至数据库存储引擎都并非难事。######回复 @wharf_zhang : 我对oracle了解不多,oracle 官方应该有example 例子,下载下来改改,编译一下,就行了######oracle能弄个博文介绍下吗?商业的和开源的数据库,我个人感觉血统关系很弱,如果也能成立,则更能证明你这个思路具有普适性。######如果一个插件就搞定了 Mysql 的Cluster、 Oracle的OGG怎么活。######只能说你没有异构平台的通信需求,对实时性要求不高。######这个与Mysql 的Cluster、 Oracle的OGG没半毛关系######应用场景不同
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。