-
Notifications
You must be signed in to change notification settings - Fork 1
/
mysql.plugin.mq.xml
241 lines (234 loc) · 10.6 KB
/
mysql.plugin.mq.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN"
"/usr/share/xml/docbook/schema/dtd/5.0/docbook.dtd" [
<!ENTITY article.author.xml SYSTEM "../common/article.author.xml">
<!ENTITY book.info.legalnotice.xml SYSTEM "../common/book.info.legalnotice.xml">
<!ENTITY book.info.abstract.xml SYSTEM "../common/book.info.abstract.xml">
]>
<article xml:base="http://netkiller.github.io/journal/"
xmlns="http://docbook.org/ns/docbook" xml:lang="zh-cn">
<articleinfo>
<title>数据库进程间通信解决方案之MQ</title>
<subtitle>http://netkiller.github.io/journal/mysql.plugin.mq.html</subtitle>
&article.author.xml;
<pubdate>$Date: 2013-12-16 13:34:20 +0800 (Thu, 16 May 2013) $</pubdate>
<releaseinfo>$Id$</releaseinfo>
&book.info.legalnotice.xml;
<abstract>
<para>你是否想过当数据库中的数据发生变化的时候出发某种操作?但因数据无法与其他进程通信(传递信号)让你放弃,而改用每隔一段时间查询一次数据变化的方法?下面的插件可以解决你的问题。</para>
<para>原文出处:<ulink url="http://netkiller.github.io/journal/mysql.plugin.fifo.html"/></para>
</abstract>
&book.info.abstract.xml;
<keywordset>
<keyword>mysql</keyword>
<keyword>plugin, udf</keyword>
<keyword>images</keyword>
</keywordset>
</articleinfo>
<section>
<title>背景</title>
<para>之前我发表过一篇文章 http://netkiller.github.io/journal/mysql.plugin.fifo.html</para>
<para>该文章中提出了通过fifo 管道,实现数据库与其他进程的通信。属于 IPC 机制(同一个OS/服务器内),后我有采用ZeroMQ重新实现了一个 RPC 机制的方案,同时兼容IPC(跨越OS/服务器)</para>
<para>各种缩写的全称 IPC(IPC :Inter-Process Communication 进程间通信),ITC(ITC : Inter Thread Communication 线程间通信)与RPC(RPC: Remote Procedure Calls远程过程调用)。</para>
<para>支持协议</para>
<screen>
inproc://my_publisher
tcp://server001:5555
ipc:///tmp/feeds/0
</screen>
</section>
<section>
<title>应用场景</title>
<para>如果你想处理数据,由于各种原因你不能在程序中实现,你可以使用这个插件。当数据库中的数据发生变化的时候出发某种操作,你可以使用这个插件。</para>
<para>有时候你的项目可能是外包的,项目结束后外包方不会在管你,你有无法改动现有代码,或者根本不敢改。你可以使用这个插件</para>
<para>采用MQ技术对数据库无任何压力,与采用程序处理并无不同,省却了写代码</para>
<para>处理方法,可以采用同步或者异步方式</para>
<example>
<title>发送短信</title>
<para>发送短信、邮件,只需要查询出相应手机号码,发送到MQ的服务端,服务端接收到手机号码后,放入队列中,多线程程序从队列中领取任务,发送短信。</para>
<screen>
select zmq_client('tcp://localhost:5555',mobile) from demo where subscribed='Y' ...;
</screen>
<para>传递多个参数,可以使用符号分隔</para>
<screen>
select zmq_client('tcp://localhost:5555',concat(name,',',mobile,', news')) from demo;
select zmq_client('tcp://localhost:5555',concat(name,'|',mobile,'|news')) from demo;
</screen>
<para>json格式</para>
<screen>
select zmq_client('tcp://localhost:5555',concat('{name:',name,', tel:',mobile,', template:news}')) from demo;
</screen>
<para>建议采用异步方式,MQ端接收到任务立即反馈 “成功”信息,因为我们不太关心是否能发送成功,本身就是盲目性的发送,手机号码是否可用我们无从得知,短信或者邮件的发送到达率不是100%,所以当进入队列后,让程序自行处理,将成功或者失败信息记录到日志中即可。</para>
</example>
<example>
<title>处理图片</title>
<para>首先查询出需要处理图片,然后将路径与分辨率传递给MQ另一端的处理程序</para>
<screen>
select zmq_client('tcp://localhost:5555',concat(image,',800x600}')) from demo;
</screen>
<para>建议采用异步方式,MQ端接收到任务立即反馈 “成功”信息</para>
</example>
<example>
<title>身份证号码校验</title>
<screen>
select zmq_client('tcp://localhost:5555',id_number) from demo;
</screen>
<para>可以采用同步方案,因为MQ款处理几乎不会延迟,直接将处理结构反馈</para>
</example>
<example>
<title>静态化案例</title>
<para>情景模拟,你的项目是你个电商项目,采用外包模式开发,项目已经开发完成。外包放不再负责维护,你现在要做静态化。增加该功能,你要检查多处与商品表相关的造作。</para>
<para>于其改代码,不如程序从外部处理,这样更保险。我们只要写一个程序将动态 URL 下载保存成静态即可,当数据发生变化的时候重新下载覆盖即可</para>
<screen>
CREATE DEFINER=`dba`@`%` TRIGGER `demo_after_insert` AFTER INSERT ON `demo` FOR EACH ROW BEGIN
select zmq_client('tcp://localhost:5555', NEW.id);
END
CREATE DEFINER=`dba`@`%` TRIGGER `demo_after_update` AFTER UPDATE ON `demo` FOR EACH ROW BEGIN
select zmq_client('tcp://localhost:5555', NEW.id);
END
CREATE DEFINER=`dba`@`%` TRIGGER `demo_after_delete` AFTER DELETE ON `demo` FOR EACH ROW BEGIN
select zmq_client('tcp://localhost:5555', NEW.id);
END
</screen>
<para>MQ 另一端的服务会下载<![CDATA[http://www.example.com/goods.php?cid=111&id=100]]>, 然后生成html页面,http://www.example.com/111/100.html</para>
<para>插入会新建页面,更新会覆盖页面,删除会删除页面</para>
<para>这样无论商品的价格,属性改变,静态化程序都会做出相应的处理。</para>
</example>
<example>
<title>数据同步案例</title>
<para>我们有多个数据库,A 库里面的数据发生变化后,要同步书库到B库,或者处理结果,或者数据转换后写入其他数据库中</para>
<para>方法也是采用触发器或者EVENT处理</para>
</example>
</section>
<section>
<title>Mysql plugin</title>
<para> 我开发了几个 UDF, 共4个 function</para>
<variablelist>
<title>UDF</title>
<varlistentry>
<term>zmq_client(sockt,message)</term>
<listitem>
<para>sockt .成功返回true,失败返回flase.</para>
</listitem>
</varlistentry>
</variablelist>
<para>有了上面的function后你就可以在begin,commit,rollback 直接穿插使用,实现在事物处理期间做你爱做的事。也可以用在触发器与EVENT定时任务中。</para>
</section>
<section>
<title>plugin 的开发与使用</title>
<para>编译UDF你需要安装下面的软件包</para>
<screen>
sudo apt-get install pkg-config
sudo apt-get install libmysqlclient-dev
sudo apt-get install gcc gcc-c++ make cmake
</screen>
<para><ulink url="https://github.com/netkiller/mysql-zmq-plugin" /></para>
<para>编译udf,最后将so文件复制到 /usr/lib/mysql/plugin/</para>
<screen>
<![CDATA[
git clone https://github.com/netkiller/mysql-zmq-plugin.git
cd mysql-zmq-plugin
cmake .
make && make install
]]>
</screen>
<para>装载</para>
<screen>
create function zmq_client returns string soname 'libzeromq.so';
create function zmq_publish returns string soname 'libzeromq.so';
</screen>
<para>卸载</para>
<screen>
drop function zmq_client;
drop function zmq_publish;
</screen>
<para>确认安装成功</para>
<screen>
<![CDATA[
mysql> SELECT * FROM `mysql`.`func` where name like 'zmq%';
+-------------+-----+--------------+----------+
| name | ret | dl | type |
+-------------+-----+--------------+----------+
| zmq_client | 0 | libzeromq.so | function |
| zmq_publish | 0 | libzeromq.so | function |
+-------------+-----+--------------+----------+
2 rows in set (0.00 sec)
]]>
</screen>
</section>
<section>
<title>插件如何使用</title>
<para>插件有很多种用法,这里仅仅一个例</para>
<para>编译zeromq server 测试程序</para>
<screen>
cd test
cmake .
make
</screen>
<para>启动服务进程</para>
<screen>
./server
</screen>
<para>发送Hello world! </para>
<screen>
<![CDATA[
mysql> select zmq_client('tcp://localhost:5555','Hello world!');
+---------------------------------------------------+
| zmq_client('tcp://localhost:5555','Hello world!') |
+---------------------------------------------------+
| Hello world! OK |
+---------------------------------------------------+
1 row in set (0.01 sec)
]]>
</screen>
<para>查看服务器端是否接收到信息。</para>
<screen>
$ ./server
Received: Hello world!
</screen>
<para>我们再将上面的例子使用触发器进一步优化</para>
<screen>
<![CDATA[
mysql> select zmq_client('tcp://localhost:5555',mobile) from demo;
+-------------------------------------------+
| zmq_client('tcp://localhost:5555',mobile) |
+-------------------------------------------+
| 13113668891 OK |
| 13113668892 OK |
| 13113668893 OK |
| 13322993040 OK |
| 13588997745 OK |
+-------------------------------------------+
5 rows in set (0.03 sec)
]]>
</screen>
<para>服务器端已经接收到数据库发过来的信息</para>
<screen>
$ ./server
Received: Hello world!
Received: 13113668891
Received: 13113668892
Received: 13113668893
Received: 13322993040
Received: 13588997745
</screen>
<para>我们可以拼装json或者序列化数据,发送给远端</para>
<screen>
<![CDATA[
mysql> select zmq_client('tcp://localhost:5555',concat('{name:',name,', tel:',mobile,'}')) from demo;
+------------------------------------------------------------------------------+
| zmq_client('tcp://localhost:5555',concat('{name:',name,', tel:',mobile,'}')) |
+------------------------------------------------------------------------------+
| {name:neo, tel:13113668891} OK |
| {name:jam, tel:13113668892} OK |
| {name:leo, tel:13113668893} OK |
| {name:jerry, tel:13322993040} OK |
| {name:tom, tel:13588997745} OK |
+------------------------------------------------------------------------------+
5 rows in set (0.03 sec)
]]>
</screen>
<para>返回数据取决于你服务端怎么编写处理程序,你可以返回true/false等等。</para>
<para>触发器以及事务处理,这里就不演示了</para>
</section>
</article>