【www.5929.com】复制介绍及搭建,PHP多进度消费队列

www.5929.com, 测试的代码主要成效:开启一个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复制是异步的且串行化的

www.5929.com 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作为高质量服务器的顶梁柱,为广大的商家和个体服务,他的历程模型比较经典,如下所示:

www.5929.com 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的简化版本。
www.5929.com 3

环境准备

master 192.168.1.5

slave 192.168.1.6

OS:Oracle Linux 6.1

MySQL:5.5.37

www.5929.com 4

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【www.5929.com】复制介绍及搭建,PHP多进度消费队列。来调用未处理的信号,PHP 5.4.0及之后的版本适用,可以巧妙的将该函数放在循环中,质量上基本没什么损失,现在援引适用。

Master配置

1)分配复制权限

主库和从库均要求举办

www.5929.com 5

2)清空日志文件

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

www.5929.com 6

亟需注意的是,若是不想清空日志文件的话,必要记录当前master的log_file和log_pos,并在上边启用复制操作时指定那八个参数或者在slave的安排文件指定。

Slave设置

1) 修改从服务器server-id

www.5929.com 7

修改完事后必要重启数据库

2)清空日志文件,同Master

3)启用复制

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

www.5929.com 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

www.5929.com 9

5)确认Slave是还是不是和Mater成功通讯。如果Slave_IO_Running和Slave_SQL_Running都是yes,则印证配置成功

www.5929.com 10

测试

Master成立数据库

www.5929.com 11

Slave查看数据库已一起

www.5929.com 12

Master创立表插入数据

www.5929.com 13

Slave查看

www.5929.com 14

经过上述验证,可以看出主服务器上的修改可以正常同步到从服务器。

【www.5929.com】复制介绍及搭建,PHP多进度消费队列。补偿表明

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

www.5929.com 15

如此那般就足以保留file和position的消息,在新搭建一个slave的时候,还原完数据库,file和position的音讯也随着更新,接着再start
slave 就能够很便捷的完毕增量同步。

查看进程,在server->start 后,拉起workNum+2(master,manager进度)。

3)数据丢是没有主意苏醒

PHP安装修信号量

PHP通过pcntl_signal安装信号,函数注明如下所示:

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

其多个参数restart_syscalls不太好了然,找了成千成万素材,也没太Charles解,经过试验发现,那个参数对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参数。同时二进制日志也无法不启用。

www.5929.com 16

自然,扩大复制的级联层次,同一个改变传到最尾部的Slave所急需经过的MySQL也会越多,同样可能引致延时较长的高风险。若是条件允许,倾向于通过拆分成多少个Replication集群来化解。

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

www.5929.com 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. 设置子进度为会话CEO,进度CEO。
  3. 再也fork,父进度退出,子进程继续运行。
  4. 复原文件掩码为0
  5. 切换当前目录到根目录/

第2步是为第1步做准备,设置进程为会话总裁,要求条件是进度非经过COO,由此做首次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

别的,会话、进程组、进度的关联如下图所示,那张图有助于更好的明亮。
www.5929.com 18

时至明日,你也可以轻松地造出一个daemon进度了。

www.5929.com 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进程也脱离。

www.5929.com 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检测三回。

www.5929.com 21

1)基于语句的复制

其他设计

别的还加了三个相比较实用的机能,一个是worker进度运行时刻限制,一个是worker进度循环处理次数限制,幸免长日子循环进程出现内存溢出等意外景况。时间默许是1钟头,运行次数默许是10w次。

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

代码已经松开github中,有趣味的可以尝试,不接济windows哦,有怎么着错误还望提议来。

主进度仍然1827,不过工作进程就被reload的了。

2)基于行的复制

参照文章

凭回忆想到的参阅小说,查了很多遗忘了

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

然后实施退出

3)混合类型的复制

www.5929.com 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上开创一个库

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

Leave a Comment.