udf:用户自定义函数缩写
任务(job)提交给gearman server,任务的提交者可以是mysql,因为他有触发器,可以进行 update,
用户自定义函数有两个,通过调用函数来触发 gearman 发给server1的4730端口(server-set的设置)
使用json 格式的原因是mysql与redis数据结构不同,而 json数据支持跨平台 ,所以用json格式
把任务发给gearman server
server交给(多个)worker处理, worker是一段程序 可以是java python php
在worker中,php-gearman模块作用是将数据传过来,php-redis模块的作用是存储数据
- 前面的实验中,如果客户端的请求是修改数据,即 mysql被update(数据被更新)的话, redis和mysql两者没同步就会导致数据不一致的问题,所以为了解决这两者数据不同步的问题,我们这里利用Gearman这个工具,让mysql中数据有更新时,主动触发redis进行同步。
- redis只有在他的数据过期或没有缓存的时侯才会去找mysql拿数据,所以我们希望在mysql有update操作后,会自动的触发redisserver。
数据流向:job(mysql trigger) mysql-gearman ----> gearman server ----> worker(php-gearman、php-redis、 set)
Gearman
简介
- Gearman是一个支持分布式的任务分发框架,是一套用来把程式需求委派给机器,提供通用的程序框架来将任务分发在机器运算。它同时具备并行工作的能力、负载均衡处理的能力,以及在不同程序语言之间沟通的能力。
- Gearman提供了一个通用的应用程序框架,用于将工作转移到更适合于工作的其他机器或流程。它允许你并行工作,负载平衡处理,并在语言间调用函数。它可用于从高可用性网站到传输数据库复制事件的各种应用程序。换句话说,它是分布式处理交流的神经系统。
运行过程
一个Gearman请求的处理过程涉及三个角色:Client -> Job -> Worker
。
- Gearman Job Server: Gearman 核心程序,需要编译安装并以守护进程形式运行在后台。
- Gearman Client:可以理解为任务的请求者。
- Gearman Worker:任务的真正执行者,一般需要自己编写具体逻辑并通过守护进程方式
运行,Gearman Worker 接收到 Gearman Client 传递的任务内容后,会按顺序处理。
因为 Client,Worker 并不限制用一样的语言,所以有利于多语言多系统之间的集成。
甚至我们通过增加更多的 Worker,可以很方便的实现应用程序的分布式负载均衡架构。
优点
- 开源它是免费的!(在这个词的两个意思中)Gearman有一个活跃的开源社区,如果你需要帮助或者想贡献,很容易参与进来。担心授权?Gearman是BSD。
- 多语言 - 有一些语言的接口,这个列表正在增长。您也可以选择使用一种语言提交工作的客户端编写异构应用程序,并在另一种语言中执行该工作的工作人员。
- ==灵活 ==- 您不受限于任何特定的设计模式。您可以使用您选择的任何模型快速组合分布式应用程序,这些选项之一是Map / Reduce。
- 快速 - Gearman有一个简单的协议和接口,用C / C ++编写的优化的,线程化的服务器可以最大限度地减少应用程序开销。
- 嵌入式 - 由于Gearman速度快,重量轻,适用于各种尺寸的应用。以最小的开销引入现有的应用程序也很容易。
- 没有单点故障- Gearman不仅可以帮助扩展系统,而且还可以通过容错方式实现。
- 消息大小没有限制 - Gearman支持最多4gig的单个消息。需要做更大的事情?没问题Gearman可以大块消息。
Gearman如何工作?
- 一个Gearman驱动的应用程序由三部分组成:
一个客户端,一个工作者和一个作业服务器
。客户端负责创建要运行的作业并将其发送到作业服务器。作业服务器将找到可以运行作业并转发作业的合适工作人员。工作人员执行客户端请求的工作,并通过作业服务器向客户端发送响应。Gearman提供您的应用程序调用的客户端和工作者API来与Gearman作业服务器(也称为gearmand)交谈,因此您不需要处理网络或作业的映射。在内部,gearman客户端和工作者API使用TCP套接字与作业服务器进行通信。
实验流程
- 此实验基于上一篇博客的实验环境,需要提前在三个节点搭建好相应的服务。
- 我们此实验要编写的 mysql 触发器,就相当于 Gearman 的客户端。修改表,插入表就相当于直接下发任务。然后通过
lib_mysqludf_json UDF
库函数将关系数据映射为 JSON 格式,然后在通过gearman-mysql-udf
插件将任务加入到 Gearman 的任务队列中,最后通过redis_worker.php
,也就是 Gearman 的 worker 端来完成 redis 数据库的更新。
server1(lnmp)
- 下载gearman的软件包进行安装。
lftp 172.25.11.250:/pub/redis/rhel7> get gearmand-1.1.12-18.el7.x86_64.rpm
lftp 172.25.11.250:/pub/redis/rhel7> mget libgearman-*
lftp 172.25.11.250:/pub/redis/rhel7> mget libevent-devel-2.0.21-4.el7.x86_64.rpm
[root@server1 ~]# yum install gearmand-1.1.12-18.el7.x86_64.rpm libevent-devel-2.0.21-4.el7.x86_64.rpm libgearman-* -y
- 开启gearmand服务,查看他所开启的端口为4730。
[root@server1 ~]# systemctl start gearmand
[root@server1 ~]# netstat -antlp
- 编写gearman的worker端。修改worker.php文件,将redis的ip改为我们redis服务器的ip。
[root@server1 ~]# vim worker.php
<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
$redis = new Redis();
$redis->connect('172.25.11.2', 6379);
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, $work->name); ##这条语句就是将 id 作 KEY 和name 作 VALUE 分开存储,需要和前面写的 php 测试代码的存取一致。
}
?>
[root@server1 ~]# php -m | grep gearman
- 下载php的gearman扩展,解压,并进行phpize。
lftp 172.25.11.250:/pub/redis> get gearman-1.1.2.tgz
[root@server1 ~]# tar zxf gearman-1.1.2.tgz
[root@server1 /]# cd ~/gearman-1.1.2
[root@server1 gearman-1.1.2]# phpize
- 编译并安装,加上我们所需要的编译参数。
[root@server1 gearman-1.1.2]# ./configure --help
[root@server1 gearman-1.1.2]# ./configure --with-gearman
[root@server1 gearman-1.1.2]# make && make install
- 按照redis.ini的模版创建gearman.ini文件,编辑为我们gearman的模块,编辑完后重启apache,并过滤查看php中有没有gearman的模块。
[root@server1 gearman-1.1.2]# cd /usr/lib64/php/modules/
[root@server1 modules]# cd /etc/php.d/
[root@server1 php.d]# cp redis.ini gearman.ini
[root@server1 php.d]# vim gearman.ini
[root@server1 php.d]# cat gearman.ini
extension=gearman.so
[root@server1 php.d]# systemctl restart httpd
[root@server1 php.d]# php -m | grep gearman
gearman
- 将修改后的php文件移至/usr/local下,用php以静默的模式运行。
[root@server1 ~]# mv worker.php /usr/local/
[root@server1 ~]# nohup php /usr/local/worker.php & #后台运行worker
[1] 17361
[root@server1 ~]# ps ax
注意:我们这里把gearman server和处理job的gearman worker放在同一台主机了,实际生产环境中是分离的。
server3(mysql)
- 修改之前的test.sql文件,此时将数据库直接导入是会报错的。
[root@server3 ~]# vim test.sql
- 安装
lib_mysqludf_json
。lib_mysqludf_json UDF库函数将关系数据映射成json格式,通常,数据库中的数据映射成json格式是通过程序来转换的。(因为mysql与redis的数据类型不同所以必须转换为json标准数据类型。)
lftp 172.25.11.250:/pub/redis> get lib_mysqludf_json-master.zip
[root@server3 ~]# yum install unzip -y
[root@server3 lib_mysqludf_json-master]# yum install gcc -y
[root@server3 lib_mysqludf_json-master]# yum install mysql-devel -y #安装所需依赖
[root@server3 lib_mysqludf_json-master]# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
- 此时,查看mysql的模块目录。
[root@server3 plugin]# pwd
/usr/lib64/mysql/plugin
[root@server3 plugin]# ls
- 在数据库中查询mysql的模块目录。
MariaDB [(none)]> show global variables like 'plugin_dir';
- 拷贝lib_mysqludf_json.so模块到mysql模块目录下。
[root@server3 plugin]# cp ~/lib_mysqludf_json-master/lib_mysqludf_json.so .
[root@server3 plugin]# pwd
/usr/lib64/mysql/plugin
[root@server3 plugin]# ll lib_mysqludf_json.so
- 注册UDF函数,并查看函数。
MariaDB [(none)]> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';
MariaDB [(none)]> select * from mysql.func;
- 安装gearman-mysql-udf,这个插件用来管理调用gearman的分布式的队列。
lftp 172.25.11.250:/pub/redis> get gearman-mysql-udf-0.6.tar.gz
[root@server3 ~]# tar zxf gearman-mysql-udf-0.6.tar.gz
- 解压后编译,指定模块的目录。
[root@server3 ~]# cd gearman-mysql-udf-0.6
[root@server3 gearman-mysql-udf-0.6]# ls
[root@server3 gearman-mysql-udf-0.6]# ./configure --with-mysql --libdir=/usr/lib64/mysql/plugin
- 发现编译失败,因为缺少所需要的依赖,我们安装依赖后继续编译。
[root@server1 ~]# scp gearmand-1.1.12-18.el7.x86_64.rpm libgearman-1.1.12-18.el7.x86_64.rpm libgearman-devel-1.1.12-18.el7.x86_64.rpm libevent-devel-2.0.21-4.el7.x86_64.rpm server3:
[root@server3 ~]# yum install * -y
[root@server3 ~]# cd -
/root/gearman-mysql-udf-0.6
[root@server3 gearman-mysql-udf-0.6]# ./configure --with-mysql --libdir=/usr/lib64/mysql/plugin
[root@server3 gearman-mysql-udf-0.6]# make && make install
- 此时模块目录下出现了我们安装的
gearman_mysql_udf
的模块。
[root@server3 gearman-mysql-udf-0.6]# cd /usr/lib64/mysql/plugin
[root@server3 plugin]# ls
- 注册并查看UDF函数。
MariaDB [(none)]> CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so';
MariaDB [(none)]> CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';
MariaDB [(none)]> select * from mysql.func;
- 指定gearman服务的信息,这里gearman服务器为server1,端口为4730。
MariaDB [(none)]> SELECT gman_servers_set('172.25.11.1:4730');
- 再次导入数据库。(这里是根据实际情况编写的mysql触发器)
[root@server3 ~]# mysql < test.sql
MariaDB [(none)]> SHOW TRIGGERS FROM test; #查看触发器
测试
server3
- 测试,更新mysql中的数据。
MariaDB [(none)]> use test;
MariaDB [test]> update test set name='zhangyiwen' where id=1;
server2
- 查看redis,发现数据已同步。
[root@server2 init.d]# redis-cli get 1
- 刷新测试页,测试数据同步。
- 继续修改mysql中的数据测试。
MariaDB [test]> update test set name='westos' where id=2;
总结:如上,我们实现了当mysql中数据有修改时,mysql主动的去触发redis服务器,进行数据的同步。