通过Gearman实现MySQL到Redis的数据复制

日志未经声明,均为AlloVince原创。版权采用『 知识共享署名-非商业性使用 2.5 许可协议』进行许可。

对于变化频率非常快的数据来说,如果还选择传统的静态缓存方式(File System等)展示数据,可能在缓存的存取上会有很大的开销,并不能很好的满足需要,而Redis这样基于内存的NoSQL数据库,就非常适合担任实时数据的容器。

但是往往我们又有数据可靠性的需求,采用MySQL作为数据存储,不会因为内存问题而引起数据丢失,同时也可以利用关系数据库的特性实现很多功能。

所以就会很自然的想到是否可以采用MySQL作为数据存储引擎,Redis则作为Cache。而这种需求目前还没有看到有特别成熟的解决方案或工具,因此本文将尝试采用Gearman+PHP+MySQL UDF的组合异步实现MySQL到Redis的数据复制。

MySQL到Redis数据复制方案

无论MySQL还是Redis,自身都带有数据同步的机制,像比较常用的MySQL的Master/Slave模式,就是由Slave端分析Master的binlog来实现的,这样的数据复制其实还是一个异步过程,只不过当服务器都在同一内网时,异步的延迟几乎可以忽略。

那么理论上我们也可以用同样方式,分析MySQL的binlog文件并将数据插入Redis。但是这需要对binlog文件以及MySQL有非常深入的理解,同时由于binlog存在Statement/Row/Mixedlevel多种形式,分析binlog实现同步的工作量是非常大的。

因此这里选择了一种开发成本更加低廉的方式,借用已经比较成熟的MySQL UDF,将MySQL数据首先放入Gearman中,然后通过一个自己编写的PHP Gearman Worker,将数据同步到Redis。比分析binlog的方式增加了不少流程,但是实现成本更低,更容易操作。

Gearman的安装与使用

Gearman是一个支持分布式的任务分发框架。设计简洁,获得了非常广泛的支持。一个典型的Gearman应用包括以下这些部分:

  • Gearman Job Server:Gearman核心程序,需要编译安装并以守护进程形式运行在后台
  • Gearman Client:可以理解为任务的收件员,比如我要在后台执行一个发送邮件的任务,可以在程序中调用一个Gearman Client并传入邮件的信息,然后就可以将执行结果立即展示给用户,而任务本身会慢慢在后台运行。
  • Gearman Worker:任务的真正执行者,一般需要自己编写具体逻辑并通过守护进程方式运行,Gearman Worker接收到Gearman Client传递的任务内容后,会按顺序处理。

以前曾经介绍过类似的后台任务处理项目Resque。两者的设计其实非常接近,简单可以类比为:

  • Gearman Job Server:对应Resque的Redis部分
  • Gearman Client:对应Resque的Queue操作
  • Gearman Worker:对应Resque的Worker和Job

这里之所以选择Gearman而不是Resque是因为Gearman提供了比较好用的MySQL UDF,工作量更小。

安装Gearman及PHP Gearman扩展

以下均以Ubuntu12.04为例。

apt-get install gearman gearman-server libgearman-dev

检查Gearman的运行状况:

/etc/init.d/gearman-job-server status
* gearmand is running

说明Gearman已经安装成功。

PHP的Gearman扩展可以通过pecl直接安装

pecl install gearman
echo "extension=gearman.so" > /etc/php5/conf.d/gearman.ini
service php5-fpm restart

但是实测发现ubuntu默认安装的gearman版本过低,直接运行pecl install gearman会报错

configure: error: libgearman version 1.1.0 or later required

因此Gearman + PHP扩展建议通过编译方式安装,这里为了简单说明,选择安装旧版本扩展:

pecl install gearman-1.0.3

Gearman + PHP实例

为了更容易理解后文Gearman的运行流程,这里不妨从一个最简单的Gearman实例来说明,比如我们要进行一个文件处理的操作,首先编写一个Gearman Client并命名为client.php:

<?php
$client = new GearmanClient();
$client->addServer();
$client->doBackground('writeLog', 'Log content');
echo '文件已经在后台操作';

运行这个文件,相当于模拟用户请求一个Web页面后,将处理结束的信息返回用户:

php client.php

查看一下Gearman的状况:

(echo status ; sleep 0.1) | netcat 127.0.0.1 4730

可以看到输出为

writeLog        1       0       0
.

说明我们已经在Gearman中建立了一个名为writeLog的任务,并且有1个任务在队列等待中。

而上面的4列分别代表当前的Gearman的运行状态:

  1. 任务名称
  2. 在等待队列中的任务
  3. 正在运行的任务
  4. 正在运行的Worker进程

可以使用watch进行实时监控:

watch -n 1 "(echo status; sleep 0.1) | nc 127.0.0.1 4730"

然后我们需要编写一个Gearman Worker命名为worker.php:

<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('writeLog', 'writeLog');
while($worker->work());function writeLog($job)
{$log = $job->workload();file_put_contents(__DIR__ . '/gearman.log', $log . "\n", FILE_APPEND | LOCK_EX);
}

Worker使用一个while死循环实现守护进程,运行

php worker.php

可以看到Gearman状态变为:

writeLog        0       0       1

同时查看同目录下gearman.log,内容应为从Client传入的值Log content

通过MySQL UDF + Trigger同步数据到Gearman

MySQL要实现与外部程序互通的最好方式还是通过MySQL UDF(MySQL user defined functions)来实现。为了让MySQL能将数据传入Gearman,这里使用了lib_mysqludf_json和gearman-mysql-udf的组合。

安装lib_mysqludf_json

使用lib_mysqludf_json的原因是因为Gearman只接受字符串作为入口参数,可以通过lib_mysqludf_json将MySQL中的数据编码为JSON字符串

apt-get install libmysqlclient-dev
wget https://github.com/mysqludf/lib_mysqludf_json/archive/master.zip
unzip master.zip
cd lib_mysqludf_json-master/
rm lib_mysqludf_json.so
gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c

可以看到重新编译生成了 lib_mysqludf_json.so 文件,此时需要查看MySQL的插件安装路径:

mysql -u root -pPASSWORD --execute="show variables like '%plugin%';"
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| plugin_dir    | /usr/lib/mysql/plugin/ |
+---------------+------------------------+

然后将 lib_mysqludf_json.so 文件复制到对应位置:

cp lib_mysqludf_json.so /usr/lib/mysql/plugin/

最后登入MySQL运行语句注册UDF函数:

CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';

安装gearman-mysql-udf

方法几乎一样:

apt-get install libgearman-dev
wget https://launchpad.net/gearman-mysql-udf/trunk/0.6/+download/gearman-mysql-udf-0.6.tar.gz
tar -xzf gearman-mysql-udf-0.6.tar.gz
cd gearman-mysql-udf-0.6
./configure --with-mysql=/usr/bin/mysql_config --libdir=/usr/lib/mysql/plugin/
make && make install

登入MySQL运行语句注册UDF函数:

CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so';
CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';

最后指定Gearman服务器的信息:

SELECT gman_servers_set('127.0.0.1:4730');

通过MySQL触发器实现数据同步

最终同步哪些数据,同步的条件,还是需要根据实际情况决定,比如我希望将数据表data的数据在每次更新时同步,那么编写Trigger如下:

DELIMITER $$
CREATE TRIGGER datatoredis AFTER UPDATE ON dataFOR EACH ROW BEGINSET @ret=gman_do_background('syncToRedis', json_object(NEW.id as `id`, NEW.volume as `volume`)); END$$
DELIMITER ;

尝试在数据库中更新一条数据查看Gearman是否生效。

Gearman PHP Worker将MySQL数据异步复制到Redis

Redis作为时下当热的NoSQL缓存解决方案无需过多介绍,其安装及使用也非常简单:

apt-get install redis-server
pecl install redis
echo "extension=redis.so" > /etc/php5/conf.d/redis.ini

然后编写一个Gearman Worker:redis_worker.php

#!/usr/bin/env php
<?
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');$redis = new Redis();
$redis->connect('127.0.0.1', 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, $workString);
}

最后需要将Worker在后台运行:

nohup php redis_worker.php &

通过这种方式将MySQL数据复制到Redis,经测试单Worker基本可以瞬时完成。

注意点

在实际操作中发现,Gearman UDF在每次MySQL服务重启后会丢失已经设置的服务器信息。因为时间有限没有深入的调查原因,而用了曲线救国的解决方法,让MySQL在每次服务启动时自动运行一次设置语句:

vi /var/lib/mysql/init_file.sql

加入

SELECT gman_servers_set('127.0.0.1:4730');

然后在/etc/mysql/my.cnf的[mysqld]小节下加入

init-file=/var/lib/mysql/init_file.sql

然后重启服务。

通过Gearman实现MySQL到Redis的数据复制相关推荐

  1. php resque gearman,通过Gearman实现MySQL到Redis的数据同步

    对于变化频率非常快的数据来说,如果还选择传统的静态缓存方式(Memocached.File System等)展示数据,可能在缓存的存取上会有很大的开销,并不能很好的满足需要,而Redis这样基于内存的 ...

  2. Gearman + Nodejs + MySQL UDF异步实现 MySQL 到 Redis 的数据同步

    目录 1, 环境 2, Redis简介 3, Gearman简介 4, MySQL - Redis配合使用方案 4, 软件安装 5, MySQL UDF + Trigger同步数据到Gearman 6 ...

  3. nodejs mysql 异步_Gearman + Nodejs + MySQL UDF异步实现 MySQL 到 Redis 的数据同步

    1, 环境 CentOS, MySQL, Redis, Nodejs Redis是一个开源的K-V内存数据库,它的key可以是string/set/hash/list/...,因为是基于内存的,所在访 ...

  4. Mysql到Redis的数据协议(可以按照写redis的协议,自测已经成功,key值可以自己变化,不一定非要是id)

    redis-cli命令行工具有一个批量插入模式,是专门为批量执行命令设计的.这第一步就是把Mysql查询的内容格式化成redis-cli可用的数据格式. 原理是把要插入到Redis的数据直接转成Red ...

  5. 如何保持mysql和redis中数据的一致性?

    Redis 的数据一致性方案分析 一般的业务场景都是读多写少的,当客户端的请求太多,对数据库的压力越来越大,引入缓存来降低数据库的压力是必然选择,目前业内主流的选择基本是使用 Redis 作为数据库的 ...

  6. mysql php 迁移_MySQL数据复制、迁移、转换

    本文总结各种场景下的mysql数据复制.迁移.转换.1.导入.导出利用mysqldump命令将数据文件导出成一个文本文件,这在不同场景下 本文总结各种场景下的mysql数据复制.迁移.转换. 1.导入 ...

  7. 如何基于MySQL及Redis搭建统一的kv存储服务 | 秦波

    一.MySQL+Redis常用部署方式 1.1  拓扑 1.2  特点 业务层通过双写同时写MySQL及Redis.读通常在Redis,若读取不到,则从MySQL读取,然后将数据同步到Redis,Re ...

  8. gearman mysql redis_gearman redis mysql 数据同步

    一.mysql数据库操作: [root@localhost html]# mysql -u root -p mysql> create database mytest; mysql> CR ...

  9. Mysql和Redis数据同步该怎么做

    前言 算法血拼:Google+百度+Alibaba+字节+Tencent+网易+360+拼夕夕+美团 不知不觉双11就来了,轰轰烈烈的秋招也完美结束了,不知算法与数据结构成为了多少小伙伴进击大厂的绊脚 ...

最新文章

  1. Python源码剖析学习二
  2. console.log 如何打印对象
  3. linux下的tmpfs目录重启后文件全部消失
  4. DLL入门浅析(3)——从DLL中导出变量
  5. python画同心圆程序_python – matplotlib:如何在给定的半径范围内绘制同心圆
  6. arcgis栅格邻域统计_ArcGIS 从基础到实战书正式出版,易智瑞技术总裁沙志友沙总推荐并亲自写序...
  7. spark broadcast的TorrentBroadcast实现
  8. bzoj 1113: [Poi2008]海报PLA(栈)
  9. Nginx源码分析 - HTTP模块篇 - TCP连接建立过程(21)
  10. cisco路由器如何查看内网流量情况
  11. 计算机学win7画图,win7自带画图工具(mspaint.exe)
  12. 小红书前端开发面试经验分享
  13. linux安装xbox无线手柄,win10系统如何连接xbox360无线手柄
  14. android 怎么去掉标题,android中如何去掉标题栏
  15. oracle OCP认证经验分享
  16. Tone Mapping Correction
  17. 微信迎来最新改版,做这几款微信插件提高用户体验!
  18. PAT Queueing at Bank(字符串处理)
  19. Safety和Security的区别
  20. AAAI 2022高分被拒?别难过!试试这个模板给Chair发个邮件捞一下吧!

热门文章

  1. urllib库用POST请求模仿有道在线翻译
  2. 2022年5月协会与各专委会大事记
  3. Could not find any downloads that satisfy the requirement tensorflow
  4. win10鼠标右键添加命令提示符打开
  5. 0011基于单片机电子密码锁控制系统设计
  6. HTML生成word文档
  7. 彻底搞懂为什么重写equals还要重写hashcode?
  8. 计算机内区位码默认是几进制,汉字的区位码怎么转换成十六进制?
  9. RobotFramework-自定义远程java关键字库能否返回Map类型
  10. 静电场边值问题及其求解