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产生随机字符串函数
Dec 06 PHP
深入分析php之面向对象
May 15 PHP
注意:php5.4删除了session_unregister函数
Aug 05 PHP
PHP6 中可能会出现的新特性预览
Apr 04 PHP
ThinkPHP处理Ajax返回的方法
Nov 22 PHP
php递归遍历多维数组的方法
Apr 18 PHP
PHP与Ajax相结合实现登录验证小Demo
Mar 16 PHP
php基于dom实现的图书xml格式数据示例
Feb 03 PHP
PHP抽象类与接口的区别实例详解
May 09 PHP
PhpStorm的使用教程(本地运行PHP+远程开发+快捷键)
Mar 26 PHP
PHP实现本地图片转base64格式并上传
May 29 PHP
PHP连接MSSQL数据库案例,PHPWAMP多个PHP版本连接SQL Server数据库
Apr 16 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
windows下PHP APACHE MYSQ完整配置
2007/01/02 PHP
php的ajax简单实例
2014/02/27 PHP
PHPExcel实现表格导出功能示例【带有多个工作sheet】
2018/06/13 PHP
laravel框架语言包拓展实现方法分析
2019/11/22 PHP
关于javascript document.createDocumentFragment()
2009/04/04 Javascript
JS中confirm,alert,prompt函数使用区别分析
2010/04/01 Javascript
jquery ajax学习笔记2 使用XMLHttpRequest对象的responseXML
2011/10/16 Javascript
利用js(jquery)操作Cookie的方法说明
2013/12/19 Javascript
解析JavaScript数组方法reduce
2016/12/12 Javascript
bootstrap+jQuery实现的动态进度条功能示例
2017/05/25 jQuery
vue 如何添加全局函数或全局变量以及单页面的title设置总结
2017/06/01 Javascript
微信小程序项目实践之主页tab选项实现
2018/07/18 Javascript
Vue-cli3项目配置Vue.config.js实战记录
2018/07/29 Javascript
微信小程序框架wepy之动态控制类名
2018/09/14 Javascript
JavaScript解析机制与闭包原理实例详解
2019/03/08 Javascript
解决layui动态加载复选框无法选中的问题
2019/09/20 Javascript
简单了解JavaScript arguement原理及作用
2020/05/28 Javascript
toString.call()通用的判断数据类型方法示例
2020/08/28 Javascript
解决vue项目运行提示Warnings while compiling.警告的问题
2020/09/18 Javascript
design vue 表格开启列排序的操作
2020/10/28 Javascript
[05:04]DOTA2上海特级锦标赛主赛事第二日TOP10
2016/03/04 DOTA
python使用mysqldb连接数据库操作方法示例详解
2013/12/03 Python
Python脚本实现自动将数据库备份到 Dropbox
2017/02/06 Python
python实现周期方波信号频谱图
2018/07/21 Python
面向初学者的Python编辑器Mu
2018/10/08 Python
Django之模型层多表操作的实现
2019/01/08 Python
Appium+python自动化之连接模拟器并启动淘宝APP(超详解)
2019/06/17 Python
pyqt5中QThread在使用时出现重复emit的实例
2019/06/21 Python
python用for循环求和的方法总结
2019/07/08 Python
Python Django 添加首页尾页上一页下一页代码实例
2019/08/21 Python
Django实现随机图形验证码的示例
2020/10/15 Python
美国面料纺织品商城:Fabric.com
2017/06/28 全球购物
酒店总经理欢迎词
2014/01/08 职场文书
《藏戏》教学反思
2016/02/23 职场文书
一篇文章带你深入了解Mysql触发器
2021/08/02 MySQL
「Manga Time Kirara MAX」2022年5月号封面公开
2022/03/21 日漫