PHP使用SWOOLE扩展实现定时同步 MySQL 数据


Posted in PHP onApril 09, 2017

南宁公司和几个分公司之间都使用了呼叫系统,然后现在需要做一个呼叫通话数据分析,由于分公司的呼叫服务器是在内网,通过技术手段映射出来,分公司到南宁之间的网络不稳定,所以需要把分公司的通话数据同步到南宁。

本身最简单的方法就是直接配置MySQL的主从同步就可以同步数据到南宁来了。但是销售呼叫系统那边的公司不给MySQL权限我们。 所以这个方法只能放弃了。

于是我们干脆的想,使用PHP来实现定时一个简易的PHP定时同步工具,然后PHP进程常驻后台运行,所以首先就先到了一个PHP组件:SWOOLE,经过讨论,分公司的每天半天生成的数据量最大在5000条左右,所以这个方案是可行,就这样干。

我们使用PHP SWOOLE 做一个异步的定时任务系统。

本身MySQL数据库的主从同步是通过解析Master库中的binary-log来进行同步数据到从库的。然而我们使用PHP来同步数据的时候,那么只能从master库分批查询数据,然后插入到南宁的slave库来了。

这里我们使用的框架是 ThinkPHP 3.2 .

首先安装PHP扩展: SWOOLE,因为没有使用到特别的功能,所以这里我们使用pecl来快速安装:

pecl install swoole

安装完成后在 php.ini 里面加入 extension="swoole.so" 安装完成后,我们使用 phpinfo() 来检查是否成功了.

PHP使用SWOOLE扩展实现定时同步 MySQL 数据

安装成功了,我们就来写业务.

服务端

1、首先启动一个后台的服务端,监听端口9501

public function index()
{
 $serv = new \swoole_server("0.0.0.0", 9501);
 $serv->set([
  'worker_num' => 1,//一般设置为服务器CPU数的1-4倍
  'task_worker_num' => 8,//task进程的数量
  'daemonize' => 1,//以守护进程执行
  'max_request' => 10000,//最大请求数量
  "task_ipc_mode " => 2 //使用消息队列通信,并设置为争抢模式
 ]);
 $serv->on('Receive', [$this, 'onReceive']);//接收任务,并投递
 $serv->on('Task', [$this, 'onTask']);//可以在这个方法里面处理任务
 $serv->on('Finish', [$this, 'onFinish']);//任务完成时候调用
 $serv->start();
}

2、接收和投递任务

public function onReceive($serv, $fd, $from_id, $data)
{
 //使用json_decode 解析任务数据
 $areas = json_decode($data,true);
 foreach ($areas as $area){
  //投递异步任务
  $serv->task($area);
 }
}

3、任务执行,数据从master库查询和写入到slave数据库

public function onTask($serv, $task_id, $from_id, $task_data)
{
 $area = $task_data;//参数是地区编号
 $rows = 50; //每页多少条
 //主库地址,根据参数地区($area)编号切换master数据库连接
 //从库MySQL实例,根据参数地区($area)编号切换slave数据库连接
 //由于程序是常驻内存的,所以MySQL连接可以使用长连接,然后重复利用。要使用设计模式的,可以使用对象池模式
 Code......

 //master 库为分公司的数据库,slave库为数据同步到南宁后的从库
 Code......

 //使用$sql获取从库中最大的自增: SELECT MAX(id) AS maxid FROM ss_cdr_cdr_info limit 1
 $slaveMaxIncrementId = ...;

 //使用$sql获取主库中最大的自增: SELECT MAX(id) AS maxid FROM ss_cdr_cdr_info limit 1
 $masterMaxIncrementId = ...;

 //如果相等的就不同步了
 if($slaveMaxIncrementId >= $masterMaxIncrementId){
  return false;
 }

 //根据条数计算页数
 $dataNumber = ceil($masterMaxIncrementId - $slaveMaxIncrementId);
 $eachNumber = ceil($dataNumber / $rows);
 $left = 0;

 //根据页数来进行分批循环进行写入,要记得及时清理内存
 for ($i = 0; $i < $eachNumber; $i++) {
  $left = $i == 0 ? $slaveMaxIncrementId : $left + $rows;
  $right = $left + $rows;
  //生成分批查询条件
  //$where = "id > $left AND <= $right";
  $masterData = ...;//从主库查询数据
  $slaveLastInsertId = ...;//插入到从库
  unset($masterData,$slaveLastInsertId);
 }

 echo "New AsyncTask[id=$task_id]".PHP_EOL;
 $serv->finish("$area -> OK");
}

4、任务完成时候调用

public function onFinish($serv, $task_id, $task_data)
{
 echo "AsyncTask[$task_id] Finish: $task_data".PHP_EOL;
}

客户端推送任务

到此基本完成,剩下来我们来写客户端任务推送

public function index()
{
 $client = new \swoole_client(SWOOLE_SOCK_TCP);
 if (!$client->connect('127.0.0.1', 9501, 1)) {
  throw new Exception('链接SWOOLE服务错误');
 }
 $areas = json_encode(['liuzhou','yulin','beihai','guilin']);
 //开始遍历检查
 $client->send($areas);
 echo "任务发送成功".PHP_EOL;
}

至此基本完成了,剩下的我们来写一个shell脚本定时执行:/home/wwwroot/sync_db/crontab/send.sh

#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

# 定时推送异步的数据同步任务
/usr/bin/php /home/wwwroot/sync_db/server.php home/index/index

使用crontab定时任务,我们把脚本加入定时任务

#设置每天12:30执行数据同步任务
30 12 * * * root /home/wwwroot/sync_db/crontab/send.sh
#设置每天19:00执行数据同步任务
0 19 * * * root /home/wwwroot/sync_db/crontab/send.sh

Tips: 最好推荐在里面加入写日志操作,这样好知道是任务推送、执行是否成功。

至此基本完成,程序有待优化~~~,各位看客有更好的方法欢迎提出。

PHP 相关文章推荐
PHP 字符串 小常识
Jun 05 PHP
PHP 输出缓存详解
Jun 20 PHP
删除无限分类并同时删除它下面的所有子分类的方法
Aug 08 PHP
php的chr和ord函数实现字符加减乘除运算实现代码
Dec 05 PHP
PHP递归复制、移动目录的自定义函数分享
Nov 18 PHP
php获取文章上一页与下一页的方法
Dec 01 PHP
php生成高清缩略图实例详解
Dec 07 PHP
PHP实现根据时间戳获取周几的方法
Feb 26 PHP
php简单计算年龄的方法(周岁与虚岁)
Dec 06 PHP
利用Laravel生成Gravatar头像地址的优雅方法
Dec 30 PHP
PHP面向对象程序设计之接口的继承定义与用法详解
Dec 20 PHP
Laravel监听数据库访问,打印SQL的例子
Oct 24 PHP
CentOS系统中PHP安装扩展的方式汇总
Apr 09 #PHP
PHP将身份证正反面两张照片合成一张图片的代码
Apr 08 #PHP
ThinkPHP中调用PHPExcel的实现代码
Apr 08 #PHP
yii框架无限极分类的实现方法
Apr 08 #PHP
PHP下载远程图片的几种方法总结
Apr 07 #PHP
POST一个JSON格式的数据给Restful服务实例详解
Apr 07 #PHP
详谈配置phpstorm完美支持Codeigniter(CI)代码自动完成(代码提示)
Apr 07 #PHP
You might like
php FLEA中二叉树数组的遍历输出
2012/09/26 PHP
PHP基于CURL进行POST数据上传实例
2014/11/10 PHP
大家在抢红包,程序员在研究红包算法
2015/08/31 PHP
PHP使用内置函数file_put_contents写入文件及追加内容的方法
2015/12/07 PHP
PHP创建文件,并向文件中写入数据,覆盖,追加的实现代码
2016/03/25 PHP
利用onresize使得div可以随着屏幕大小而自适应的代码
2010/01/15 Javascript
在页面上用action传递参数到后台出现乱码的解决方法
2013/12/31 Javascript
jquery无刷新验证邮箱地址实现实例
2014/02/19 Javascript
详解Javascript中的Object对象
2016/02/28 Javascript
微信小程序(应用号)简单实例应用及实例详解
2016/09/26 Javascript
js中scrollTop()方法和scroll()方法用法示例
2016/10/03 Javascript
ES6通过babel转码使用webpack使用import关键字
2016/12/13 Javascript
bootstrap警告框使用方法解析
2017/01/13 Javascript
Mac 安装 nodejs方法(图文详细步骤)
2017/10/30 NodeJs
详解服务端预渲染之Nuxt(介绍篇)
2019/04/07 Javascript
基于JS实现操作成功之后自动跳转页面
2020/09/25 Javascript
axios解决高并发的方法:axios.all()与axios.spread()的操作
2020/11/09 Javascript
[04:26]2014DOTA2国际邀请赛-Newbee顺利进入胜者组决赛 独家专访战神7
2014/07/19 DOTA
[02:21]十步杀一人,千里不留行——DOTA2全新英雄天涯墨客展示
2018/08/29 DOTA
Python 命令行非阻塞输入的小例子
2013/09/27 Python
在win和Linux系统中python命令行运行的不同
2016/07/03 Python
Python+matplotlib+numpy绘制精美的条形统计图
2018/01/02 Python
Python实现简单遗传算法(SGA)
2018/01/29 Python
python数据库操作mysql:pymysql、sqlalchemy常见用法详解
2020/03/30 Python
python 获取谷歌浏览器保存的密码
2021/01/06 Python
css3弹性盒模型(Flexbox)详细介绍
2014/10/08 HTML / CSS
无谷物狗粮:Pooch & Mutt
2018/05/23 全球购物
国贸专业个人求职信分享
2013/12/04 职场文书
开展党的群众路线教育实践活动方案
2014/02/05 职场文书
企业家王石演讲稿:坚持与放下
2014/04/27 职场文书
班组长安全工作职责
2014/07/15 职场文书
公务员个人年终总结
2015/02/12 职场文书
2016年校园社会综合治理宣传月活动总结
2016/03/16 职场文书
5分钟教你docker安装启动redis全教程(全新方式)
2021/05/29 Redis
电频谱管理的原则是什么
2022/02/18 无线电
Python使用华为API为图像设置多个锚点标签
2022/04/12 Python