PHP多进度消费队列,复制介绍及搭建

by admin on 2019年1月31日

 测试的代码首要功能:开启一个tcp服务器。然后设置了保管进程和行事进度start的回调进行更名。设置了pid_file保存了服务端启动的mast进度。

一、理论篇

引言

近期费用一个小功用,用到了队列mcq,启动一个经过消费队列数据,后面发现一个历程处理不东山再起了,又加了一个进度,过了段时间又处理不回复了……

那种方法每一遍都要修改crontab,即使经过挂掉了,不会马上的开行,要等到下次crontab执行的时候才会启动。关闭(重启)进程的时候用的是kill,那说不定会丢掉正在处理的多少,比如上面这几个事例,我们只要sleep进度尽管处理逻辑,那里为了明确看出效果,将处理时间放大到10s:

<?php
$i = 1;
while (1) {
    echo "开始第[{$i}]次循环\n";
    sleep(10);
    echo "结束第[{$i}]次循环\n";
    $i++;
}

当大家运行脚本之后,等到循环起来过后,给进程发送
kill {$pid},默许发送的是数码为15的SIGTERM信号。假设$i是从队列获得的,得到2的时候,正在处理,大家给程序发送了kill信号,和队列数据丢失一样,难题相比大,因而我要想艺术缓解这个题材。

开始第[1]次循环
结束第[1]次循环
开始第[2]次循环


[1]    28372 terminated  php t.php

MySQL复制介绍

MySQL复制就是一台MySQL服务器(slave)从另一台MySQL服务器(master)举办日志的复制然后再分析日志并行使到自身,类似Oracle中的Data
Guard。

MySQL复制有这个利益:

  • 先是是缓解宕机带来的数码不等同,因为MySQL复制可以实时备份数据;

  • 第二点是减轻数据库服务器的压力,多台服务器的特性一般比单台要好。不过MySQL复制不切合大数据量,大数据量推荐应用集群。

MySQL复制进度分成三步:

  • master将改成记录到二进制日志(binary
    log)。那一个记录过程叫做二进制日志事件,binary log events;

  • slave将master的binary log events拷贝到它的连片日志(relay log);

  • slave重做衔接日志中的事件,将转移使用到祥和的数据库中。MySQL复制是异步的且串行化的

bf88必发唯一官网 1

<?php
//创建Server对象,监听 127.0.0.1:9501端口
$serv = new swoole_server("127.0.0.1", 9501);
$serv->set(array(
    'max_request ' => 10, //reactor thread num
    'worker_num' => 4,    //worker process num
    'log_file' => 'swoole.log',
    'pid_file' => 'server.pid',
));



$serv->on('managerStart',function($serv){
    swoole_set_process_name("managerprocess");
});

$serv->on('workerStart',function($serv, $worker_id){
    if($worker_id >= $serv->setting['worker_num']) {
        swoole_set_process_name("workprocess_".($worker_id-$serv->setting['worker_num']));
    } else {
        swoole_set_process_name("workprocess_{$worker_id}");
    }
});
$serv->on('start',function($serv){
    echo "到这一步说明服务已经起来了,manager,work都已经回调start完成";
});
//监听连接进入事件
$serv->on('connect', function ($serv, $fd) {  
    echo "Client: Connect.\n";
});

//监听数据接收事件
$serv->on('receive', function ($serv, $fd, $from_id, $data) {
    $serv->send($fd, "Server: ".$data);
});

//监听连接关闭事件
$serv->on('close', function ($serv, $fd) {
    echo "Client: Close.\n";
});

//启动服务器
$serv->start(); 

1、企业中单台MySQL难题

nginx进度模型

那时我想开了nginx,nginx作为高品质服务器的台柱,为无数的公司和个体服务,他的历程模型相比较经典,如下所示:

bf88必发唯一官网 2

领队通过master进度和nginx举办互相,从/path/to/nginx.pid读取nginx
master进度的pid,发送信号给master进度,master根据不一致的信号做出区其他处理,然后上报新闻给管理员。worker是master进度fork出来的,master负责管理worker,不会去处监护人务,worker才是切实可行事务的处理者,master可以控制worker的退出、启动,当worker意外退出,master会收到子进程退出的音信,也会重复开动新的worker进度补充上来,不让业务处理受影响。nginx仍是可以平滑退出,不丢掉任何一个正值处理的多寡,更新配备时nginx可以完结不影响线上服务来加载新的布署,那在请求量很大的时候特意有用。

MySQL复制搭建

拉开服务器后

1)单点故障

经过设计

看了nginx的进模型,我们全然能够支付一个近乎的类库来满足处理mcq数据的要求,做到单文件控制所有进度、可以平滑退出、可以查看子进程情况。不须求太复杂,因为大家处理队列数据接受一定的延迟,做到nginx那样不间断服务比较劳苦,费时费劲,意义不是很大。设计的经过模型跟nginx类似,更像是nginx的简化版本。
bf88必发唯一官网 3

条件准备

master 192.168.1.5

slave 192.168.1.6

OS:Oracle Linux 6.1

MySQL:5.5.37

bf88必发唯一官网 4

bf88必发唯一官网,2)服务不可用不能够处理大批量的高并发数据请求

经过信号量设计

信号量是经过间通信的一种情势,相比不难,单作用也相比较弱,只可以发送信号给进度,进度按照信号做出不一致的拍卖。

master进度启动的时候保存pid到文件/path/to/daeminze.pid,管理员通过信号和master进度通信,master进度安装3种信号,碰着区其余信号,做出差其余处理,如下所示:

SIGINT  => 平滑退出,处理完正在处理的数据再退出
SIGTERM => 暴力退出,无论进程是否正在处理数据直接退出
SIGUSR1 => 查看进程状态,查看进程占用内存,运行时间等信息

master进程通过信号和worker进程通信,worker进程安装了2个信号,如下所示:

SIGINT  => 平滑退出
SIGUSR1 => 查看worker进程自身状态

怎么worker进度只设置2个信号呢,少了个SIGTERM,因为master进度收到信号SIGTERM今后,向worker进程发送SIGKILL信号,默认强制关闭进度即可。

worker进度是经过master进度fork出来的,那样master进度可以透过pcntl_wait来等待子进度退出事件,当有子进度退出的时候重临子进度pid,做拍卖并启动新的进度补充上来。

master进度也经过pcntl_wait来等待接受信号,当有信号到达的时候,会回到-1,那几个地方还有些坑,在下文中会详细讲。

PHP中有2种信号触发的法门,第一种办法是declare(ticks = 1);,那种频率不高,Zend每执行一遍低级语句,都会去检查进度中是还是不是有未处理的信号,现在早已很少使用了,PHP 5.3.0及此前的版本可能会用到那几个。

第二种是通过pcntl_signal_dispatch来调用未处理的信号,PHP 5.4.0及然后的本子适用,可以巧妙的将该函数放在循环中,品质上基本没什么损失,现在引进适用。

Master配置

1)分配复制权限

PHP多进度消费队列,复制介绍及搭建。主库和从库均需求实施

bf88必发唯一官网 5

2)清空日志文件

主从库都是默许开启二进制日志文件

bf88必发唯一官网 6

须要小心的是,要是不想清空日志文件的话,必要记录当前master的log_file和log_pos,并在底下启用复制操作时指定那三个参数或者在slave的配备文件指定。

Slave设置

1) 修改从服务器server-id

bf88必发唯一官网 7

修改完事后须求重启数据库

2)清空日志文件,同Master

3)启用复制

让slave连接master并开端重做master二进制日志中的事件

bf88必发唯一官网 8

master_log_pos的值为0,因为它是日记的始发地点;master_log_file是发端日志文件。要是master日志没有被清空,那里就是眼前master的日记消息

亟需留意的是,默许景况下,会联合该用户下具有的DB,如若想限定哪些DB,有3种思路

  • 在master上的/etc/my.inf中通过参数binlog-do-db、binlog-ignore-db设置需求一块的数据库

  • 在执行grant分配权限操作的时候,限定数据库

  • 在slave上限制数据库使用replicate-do-db=dbname

4)开启slave

bf88必发唯一官网 9

5)确认Slave是不是和Mater成功通讯。若是Slave_IO_Running和Slave_SQL_Running都是yes,则证实配置成功

bf88必发唯一官网 10

测试

Master成立数据库

bf88必发唯一官网 11

Slave查看数据库已同步

bf88必发唯一官网 12

Master创建表插入数据

bf88必发唯一官网 13

Slave查看

bf88必发唯一官网 14

通过以上验证,可以见到主服务器上的改动可以正常同步到从服务器。

补偿表达

1)做了MySQL主从复制以后,使用mysqldump对数据备份时,一定要小心坚守如下方式:

bf88必发唯一官网 15

那般就可以保留file和position的信息,在新搭建一个slave的时候,还原完数据库,file和position的消息也随之更新,接着再start
slave 就可以很高效的成功增量同步。

翻开进度,在server->start 后,拉起workNum+2(master,manager进度)。

3)数据丢是不曾章程复苏

PHP安装修信号量

PHP通过pcntl_signalPHP多进度消费队列,复制介绍及搭建。设置信号,函数申明如下所示:

bool pcntl_signal ( int $signo , [callback $handler [, bool $restart_syscalls = true ] )

其多少个参数restart_syscalls不太好领悟,找了成百上千资料,也没太查精晓,经过试验发现,那个参数对pcntl_wait函数接收信号有影响,当设置为缺省值true的时候,发送信号,进度用pcntl_wait收不到,必须设置为false才得以,看看上面那么些事例:

<?php
$i = 0;
while ($i<5) {
    $pid = pcntl_fork();
    $random = rand(10, 50);
    if ($pid == 0) {
        sleep($random);
        exit();
    }
    echo "child {$pid} sleep {$random}\n";
    $i++;
}

pcntl_signal(SIGINT,  function($signo) {
     echo "Ctrl + C\n";
});

while (1) {
    $pid = pcntl_wait($status);
    var_dump($pid);
    pcntl_signal_dispatch();
}

运行之后,大家对父进度发送kill -SIGINT {$pid}信号,发现pcntl_wait没有反应,等到有子进度退出的时候,发送过的SIGINT会一个个推行,比如上边结果:

child 29643 sleep 48
child 29644 sleep 24
child 29645 sleep 37
child 29646 sleep 20
child 29647 sleep 31
int(29643)
Ctrl + C
Ctrl + C
Ctrl + C
Ctrl + C
int(29646)

那是运行脚本之后登时给父进度发送了四遍SIGINT信号,等到一个子历程推出的时候,所有信号都会接触。

但当把安装信号的第多个参数设置为false

pcntl_signal(SIGINT,  function($signo) {
     echo "Ctrl + C\n";
}, false);

那时给父进度发送SIGINT信号,pcntl_wait会即时回到-1,信号对应的风云也会触发。

之所以第七个参数差不多意思就是,是不是再一次登记此信号,若是为false只登记一回,触发之后就重临,pcntl_wait就能吸纳信息,要是为true,会重新登记,不会回去,pcntl_wait收不到新闻。

此外复制方式

主主复制

master-slave只可以进行单向操作,像互联网中的半双工。master-master可以兑现服务器之间相互同步,且主主复制可以防止现身单点故障后所有种类宕机。主主复制最大的题材就是多少插入或更新争持。配置方式同主从复制,反过来让slave同步master。注意master_log_file和master_log_pos参数要与master上相应。具体可以参照那里

单一master和多slave

由一个master和四个slave组成的复制系统相比较简单。slave之间并不相互通讯,只可以与master通讯。如若写操作较少,读操作很多,可以利用。可以将读操作分布到任何slave,从而减轻master的下压力。但slave扩大到早晚数量时,slave对master的负载以及网络带宽都会变成难题。

骨干多级复制

读操作很多足以动用单一maste和多slave,但附加到一定slave后连到master的slaveIO线程太多会导致master压力增大,从而造成数据复制延时。多级复制就是为通晓决这几个题目。倘使想已毕主-从(主)-从多元复制,须求设置log-slave-updates参数。同时二进制日志也必须启用。

bf88必发唯一官网 16

本来,增添复制的级联层次,同一个变更传到最底部的Slave所需求通过的MySQL也会越多,同样可能导致延时较长的高风险。假使基准允许,倾向于通过拆分成八个Replication集群来缓解。

版权申明:来源:bestvivi,链接:

bf88必发唯一官网 17

4)数据丢失导致前者不可以正常工作

信号量和系统调用

信号量会堵塞系统调用,让系统调用立即回到,比如sleep,当进程正在sleep的时候,收到信号,sleep会登时重返剩余sleep秒数,比如:

<?php
pcntl_signal(SIGINT,  function($signo) {
     echo "Ctrl + C\n";
}, false);

while (true) {
    pcntl_signal_dispatch();
    echo "123\n";
    $limit = sleep(2);
    echo "limit sleep [{$limit}] s\n";
}

运作之后,按Ctrl + C,结果如下所示:

123
^Climit sleep [1] s
Ctrl + C
123
limit sleep [0] s
123
^Climit sleep [1] s
Ctrl + C
123
^Climit sleep [2] s

下一场查看pid_file里的master进度id是或不是是1827,上图所示。结果肯定是同样的

解决办法

daemon(守护)进程

那种经过一般设计为daemon进度,不受终端控制,不与终端交互,长日子运作在后台,而对于一个进程,我们可以经过下边多少个步骤把他提拔为一个专业的daemon进度:

protected function daemonize()
{
    $pid = pcntl_fork();
    if (-1 == $pid) {
        throw new Exception("fork进程失败");
    } elseif ($pid != 0) {
        exit(0);
    }
    if (-1 == posix_setsid()) {
        throw new Exception("新建立session会话失败");
    }

    $pid = pcntl_fork();
    if (-1 == $pid) {
        throw new Exception("fork进程失败");
    } else if($pid != 0) {
        exit(0);
    }

    umask(0);
    chdir("/");
}

拢共分五步:

  1. fork子进度,父进程退出。
  2. 设置子进度为会话主管,进度主管。
  3. 再一次fork,父进度退出,子进度继续运行。
  4. 过来文件掩码为0
  5. 切换当前目录到根目录/

第2步是为第1步做准备,设置进度为会话总监,要求条件是经过非经过首席营业官,因而做第二回fork,进度主任(父进度)退出,子进度经过posix_setsid()安装为会话首席执行官,同时也为经过主管。

第3步是为着不让进度重新决定终端,因为一个历程控制一个极限的必要条件是会话老板(pid=sid)。

第4步是为着恢复生机默许的公文掩码,幸免从前做的操作对文本掩码做了安装,带来不必要的难为。关于文件掩码,
linux中,文件掩码在创制文件、文件夹的时候会用到,文件的默许权限为666,文件夹为777,创设文件(夹)的时候会用默许值减去掩码的值作为创设文件(夹)的最后值,比如掩码022下创制文件666 - 222 = 644,创设文件夹777 - 022 = 755

掩码 新建文件权限 新建文件夹权限
umask(0) 666 (-rw-rw-rw-) 777 (drwxrwxrwx)
umask(022) 644 (-rw-r–r–) 755 (drwxr-xr-x)

第5步是切换了当前目录到根目录/,网上说防止开头运行他的目录不能被正确卸载,这么些不是太通晓。

对应5步,每一步的各个id变化音讯:

操作后 pid ppid pgid sid
开始 17723 31381 17723 31381
第一次fork 17723 1 17723 31381
posix_setsid() 17740 1 17740 17740
第二次fork 17840 1 17740 17740

其它,会话、进度组、进程的涉嫌如下图所示,那张图有助于更好的掌握。
bf88必发唯一官网 18

至今,你也得以轻松地造出一个daemon进度了。

bf88必发唯一官网 19

1、伸张MySQL数据库服务器,对数据进行备份,形成主备

指令设计

自身准备给那些类库设计6个指令,如下所示:

  1. start 启动命令
  2. restart 强制重启
  3. stop 平滑甘休
  4. reload 平滑重启
  5. quit 强制为止
  6. status 查看进度情状

 

2、确保准备的MySQL数据库服务器是相同的

启航命令

开首命令就是默许的流水线,根据默许流程走就是开行命令,启动命令会检测pid文件中是不是已经有pid,pid对应的进程是还是不是正常,是或不是须求再度开动。

上面写一个脚本去重启和终止服务端。(原理就是给mast进度发送信号)

3、主服务器宕机,备份服务器继续工作,数据有有限支撑

强制截至命令

协会者通过输入文件结合pid给master过程发送SIGTERM信号,master进度给所有子进程发送SIGKILL信号,等待所有worker进度退出后,master进度也脱离。

<?php
    $options  = 's';
    $command = getopt($options);
    $pidFile = 'server.pid';
    if(isset($command['s'])){
        if($command['s']=='stop'){
            stop();
        }else{
            reload();
        }
    }else{
        die("请输入-s stop|reload");
    }

    function stop(){
        global $pidFile;
        if (file_exists($pidFile)) {
            $pid = file_get_contents($pidFile);

            if (!swoole_process::kill($pid, 0)) {
                echo "PID :{$pid} not exist \n";
                return false;
            }
            swoole_process::kill($pid);
            //等待5秒
            $time = time();
            $flag = false;
            while (true) {
                usleep(1000);
                if (!swoole_process::kill($pid, 0)) {
                    echo "server stop at " . date("y-m-d h:i:s") . "\n";
                    if (is_file($pidFile)) {
                        unlink($pidFile);
                    }
                    $flag = true;
                    break;
                } else {
                    if (time() - $time > 5) {
                        echo "stop server fail.try again \n";
                        break;
                    }
                }
            }
            return $flag;
        } else {
            echo "pid 文件不存在,请执行查找主进程pid,kill!\n";
            return false;
        }
    }

    function reload(){
        global $pidFile;
        if (file_exists($pidFile)) {
            $sig = SIGUSR1;
            $pid = file_get_contents($pidFile);
            if (!swoole_process::kill($pid, 0)) {
                echo "pid :{$pid} not exist \n";
                return;
            }
            swoole_process::kill($pid, $sig);
            echo "send server reload command at " . date("y-m-d h:i:s") . "\n";
        } else {
            echo "pid 文件不存在,请执行查找主进程pid,kill!\n";
        }
    }

MySQL主从复制与读写分离是密切相关的

强制重启命令

强制停止命令 + 启动命令

先举办重启

读写分离是根据主从复制来落到实处的

平整甘休命令

平整停止命令,管理员给master进度发送SIGINT信号,master过程给所有子进度发送SIGINT,worker进度将自身状态标记为stoping,当worker进程下次巡回的时候会基于stoping决定为止,不在接收新的数目,等具备worker进度退出之后,master进度也退出。

bf88必发唯一官网 20

二、主从服务器工作规律

平整重启命令

平滑停止命令 + 启动命令

再查看进度

MySQL主从复制的品类:

查阅进度景况

翻开进度情状这几个借鉴了workerman的思绪,管理员给master进程发送SIGUSR1信号,告诉主进程,我要看有着进度的音信,master进程,master进度将我的过程新闻写入配置好的文本路径A中,然后发送SIGUSR1,告诉worker进度把团结的新闻也写入文件A中,由于这一个历程是异步的,不知晓worker进程曾几何时写完,所以master进度在那里等待,等所有worker进度都写入文件从此,格式化所有的新闻输出,最后输出的始末如下所示:

➜/dir /usr/local/bin/php DaemonMcn.php status
Daemon [DaemonMcn] 信息:
-------------------------------- master进程状态 --------------------------------
pid       占用内存       处理次数       开始时间                 运行时间
16343     0.75M          --             2018-05-15 09:42:45      0 天 0 时 3 分
12 slaver
-------------------------------- slaver进程状态 --------------------------------
任务task-mcq:
16345     0.75M          236            2018-05-15 09:42:45      0 天 0 时 3 分
16346     0.75M          236            2018-05-15 09:42:45      0 天 0 时 3 分
--------------------------------------------------------------------------------
任务test-mcq:
16348     0.75M          49             2018-05-15 09:42:45      0 天 0 时 3 分
16350     0.75M          49             2018-05-15 09:42:45      0 天 0 时 3 分
16358     0.75M          49             2018-05-15 09:42:45      0 天 0 时 3 分
16449     0.75M          1              2018-05-15 09:46:40      0 天 0 时 0 分
--------------------------------------------------------------------------------

伺机worker进度将经过音讯写入文件的时候,这些地方用了个比较trick的章程,每个worker进度输出一行音信,总括文件的行数,达到worker进度的行数之后表示拥有worker进度都将信息写入完结,否则,每个1s检测四次。

bf88必发唯一官网 21

1)基于语句的复制

其它布署

其余还加了三个比较实用的职能,一个是worker进度运行时刻范围,一个是worker进度循环处理次数限制,幸免长日子循环进程出现内存溢出等意外境况。时间默许是1时辰,运行次数默认是10w次。

除外,也得以支撑多职分,每个义务多少个经过独立开,统一由master进度管理。

代码已经松开github中,有趣味的可以试行,不协助windows哦,有哪些错误还望提议来。

主进程照旧1827,不过工作进程就被reload的了。

2)基于行的复制

参照小说

凭回忆想到的参阅文章,查了诸多忘记了

  1. Linux多职分编程(七)—Linux守护进度及其基础实验
  2. workerman源码

然后实施退出

3)混合类型的复制

bf88必发唯一官网 22

做事步骤:

翻看过程确实丢失了

1、MySQL从服务器开启I/O线程,项主服务器请求数据同步(获取主服务器上的二进制日志)

 

2、MySQL主服务器开启I/O线程回应从服务器

3、从服务器得到主的二进制日志写入中继日志中

4、从服务器开启SQL线程将二进制日志内容执行,完结多少同步。

试行一、使用三台服务器器,一台主两台从

mysql-master192.168.11.102

MySQL-slave1192.168.11.103

mysql-slave2192.168.11.106

一、首先在主MySQL上安装时间同步工具ntp

1、yum -y install ntp

2、编辑/etc/ntp.conf配置文件

vim/etc/ntp.conf

增加下边两句

server127.127.1.0

fudge127.127.1.0 startum 8

sed -n ‘25,28p’ /etc/ntp.conf查看

3、重启ntp服务

service ntp restart 

4、在两台从MySQL上安装ntpdate工具

yum -y install ntpdate

1、在两台从服务器上输入ntpd +主MySQL的IP地址

ntpdate 192.168.11.102将协调的小运一起到主MySQL上

2、多刷新几遍后发觉时间差越来越小

因为时间在前进的时候会有不是。所以时间同步命令要平日的去实施。所以就要设置一个周期性布署职分来化解

如此那般三台服务器的年月固然一道的了

二、安装MySQL服务

在主MySQL上配置

1、cp /usr/share/doc/mysql-server-5.1.71/my-medium.cnf

/etc/my.cnf

vim /etc/my.conf

【mysqld】中

添加log-slave-updates=true

修改server-id= 11

2、重启MySQL

假诺境遇那几个荒唐就是认证您只装了服务端而并未主客户端

3、在主上给从服务器授权

grant replication slave on *.* to

‘mysqlslave’@’192.168.11.%’ identified b y ‘123123’;

flush privileges;

4、查看授权表:mysql> show

master status;

三、编辑从服务器两台配置一样,不过server-id的数字无法平等

1、修改配置文件指定从日志索引

[root@localhost ~]# vim /etc/my.conf

添加

relay-log=relay-log-bin

relay-log-index=salve-relay-bin.index

修改server-id= 12

2、重启

/etc/init.d/mysqld restart

3、登陆MySQL授权

mysql -uroot -p123123

change

master to
master_host=’192.168.11.102′,master_user=’myslave’,master_password=’123123′

,master_log_file=’mysql-bin.000003′,master_log_pos=550;

start slave;

show slave status\G;

在主MySQL上创办一个库

查阅从服务器,操作是或不是同步。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图