基于Redis的MessageQueue队列封装

基于Redis的MessageQueue队列封装

Redis的链表List可以用来做链表,高并发的特性非常适合做分布式的并行消息传递。 github地址:https://github.com/huyanping/Zebra-Message-Queue packagist地址:https://packagist.org/packages/jenner/message_queue 左进右出 $redis->lPush($key, $value); $redis->rPop($key); 以下程序已在生产环境中正式使用。 基于Redis的PHP消息队列封装 <?php /** * Created by PhpStorm. * User: huyanping * Date: 14-8-19 * Time: 下午12:10 * * 基于Redis的消息队列封装 */ namespace Zebra\MessageQueue; class RedisMessageQueue implements IMessageQueue { protected $redis_server; protected $server; protected $port; /** * @var 消息队列标志 */ protected $key; /** * 构造队列,创建redis链接 * @param $server_config *
Continue reading 基于Redis的MessageQueue队列封装

redis主从搭建

redis主从搭建

redis安装方法见:初识Redis——邂逅 安装环境: [root@localhost redis]# redis-server –version Redis server v=2.8.7 sha=00000000:0 malloc=jemalloc-3.2.0 bits=32 build=df8b796b6fcf0127 [root@localhost redis]# cat /proc/version Linux version 2.6.18-92.el5 (mockbuild@builder16.centos.org) (gcc version 4.1.2 20071124 (Red Hat 4.1.2-42)) #1 SMP Tue Jun 10 18:49:47 EDT 2008 1、复制配置文件 #master配置文件 cp redis.conf redis-master.conf #slave配置文件 cp redis.conf redis-slave.conf #备份配置文件 cp redis.conf redis-bak.conf 2、修改配置文件 #master配置文件 #保证PID文件区分,PID文件主要用于保证守护进程单例运行 pidfile /var/run/redis-master.pid #区分LOG文件
Continue reading redis主从搭建

基于System V Message queue的PHP消息队列封装

基于System V Message queue的PHP消息队列封装

System V Message queue 是一种进程通信(IPC)的方式,方便实现生产者-消费者模型,单个或多个生产者向队列中写入消息,多个生产者再从队列中获取消息进行处理。 项目地址:https://github.com/huyanping/Zebra-Message-Queue packagist地址:https://packagist.org/packages/jenner/message_queue 该Wrapper支持: 进程通信 设置最大队列容量(字节单位) 获取当前队列数量 修改队列部分属性 注意:如果要修改队列最大容量,请确保你的脚本是运行在root下 <?php /** * Created by PhpStorm. * User: huyanping * Date: 14-8-9 * Time: 上午3:44 * * System V message queue IPC通信消息队列封装 * 如果你想修改一个队列最大能够存储的字节数,请确认你的脚本具有root权限 */ class SystemVMessageQueue implements IMessageQueue { //消息分组类型,用于将一个消息队列中的信息进行分组 private $msg_type; //队列标志 private $queue; //是否序列化 private $serialize_needed; //无法写入队列时,是否阻塞 private $block_send;
Continue reading 基于System V Message queue的PHP消息队列封装

PHP实现程序单例运行

PHP实现程序单例运行

一、场景描述: 最近我们一块业务,需要不断的监听一个目录的变化,如果目录中有文件,则启动PHP脚本处理掉。最初的方案是使用crontab执行sh脚本,脚本大概如下: SOK=`ps -ef |grep /www/sender.sh | grep -v grep|wc -l` if [[ “$SOK” < “2” ]];then for f in `ls /www/queue`; do php /www/logsender.php /www/queue/$f done 实际运行中出现了异常:ps -ef | grep xxx的方式,可能无法正确的判断进程是否正在执行,if条件永远都不会成立,使得PHP脚本永远不会执行。经过考虑后,决定建立一个独立于其他模块的,能够实现进程单例运行的类,解决这个问题。  二、方案设计 1、通过PID文件实现进程单例 2、程序启动、退出自动创建、删除PID文件,做到不需要业务代码考虑PID文件删除 3、尽量保证代码独立性,不影响业务代码 三、原理 1、启动创建PID文件 2、绑定程序退出、被杀死等信号量,用于删除PID文件 3、添加析构函数,对象被销毁时,删除PID文件 四、遇到的问题 程序正常退出时,无法捕获到信号量,不知道是不是信号量选错了,ctrl+c等信号是正常的,如果可以解决捕获程序正常退出时的信号量,则可以替代析构函数方案,更加稳定 五、代码 <?php /** * Created by PhpStorm. * User: huyanping * Date: 14-8-13
Continue reading PHP实现程序单例运行

初识Redis——邂逅

初识Redis——邂逅

最近由于一块业务系统瓶颈的原因,需要找一个能够实现数据快速汇总的工具做一个中间缓存。具体场景是这样的:服务器收集WEB机群的日志集中处理,日志中有大量重复信息,需要汇总做COUNT次数统计。最开始用的MYSQL,后来发现写入瓶颈,造成数据库写入线程阻塞,日志处理线程只能等到不然会把放在内存里的数据库写入队列塞满。后来按业务做了分表,数据库写入和日志处理都改成了多线程。仍然不能解决问题,服务器负载也飙升。最后经过组里讨论,决定采用redis。正好也趁此机会研究下。 一、安装 先说下安装环境和过程: 操作系统:centos5.4 redis版本:redis-2.8.7.tar.gz 过程如下: cd /data0/software/install mkdir install_redis cd install_redis wget http://download.redis.io/releases/redis-2.8.7.tar.gz tar zxvf redis-2.8.7.tar.gz cd redis-2.8.7 make && make install #修改配置文件,redis以守护进程模式运行 vi redis.conf daemonize yes #启动redis,指定配置文件位置 cd src/ ./redis-server /usr/local/redis/redis.conf redis-server启动服务端,需指定配置文件位置,否则会采用默认配置启动。 redis-server启动服务端,需指定配置文件位置,否则会采用默认配置启动。默认使用6379端口,据说用手机打字的四个字母,代表一个歌手。注意redis-server和redis-cli(客户端)程序都在./src目录下(汗,我找了好久)。 服务器端默认是不启动守护进程模式的,需要在配置文件中修改(daemonize yes) src下有个负载的测试工具redis-benchmark,做了个测试,和其他人的做了对比,稍微领先点,应该是机器比较牛,不到1.7秒10W并发。结果如下: 执行redis-cli启动客户端程序。这样即可和redis进行交互了。输入几个测试命令: 二、java包、php扩展安装配置 java的环境搭建比较简单,下载一个包导入就好了(经过生产环境验证,2.0.0版本在长时间保持连接的情况下,可能会出现连接中断的异常)。 php扩展安装稍麻烦点,linux安装过程如下: tar zvxf redis-2.8.7.tar.gz cd redis-2.8.7 /bin/phpize ./configure –with-php-config=bin/php-config make make install cd ..
Continue reading 初识Redis——邂逅

我的第一个github开源项目——Zebra Http Server

我的第一个github开源项目——Zebra Http Server

Zebra Http Server 项目地址:http://huyanping.github.io/zebra_http_server 一款基于PHP的HTTP服务器,只是一个实验性项目;具有以下主要特征: 1、支持并发请求(基于PCNTL); 2、支持GET方法; 3、支持文本文件、二进制文件请求; 4、支持几种文件类型,支持几种HTTP状态码; 5、支持php动态语言,采用标准cgi接口; 6、预留了其他web脚本语言的接口; 该项目有待改进,希望有共同兴趣的同学一起参与。 二期修改计划完成以下工作: 1、修改Mpass框架,目前的并发方式太过浪费资源,改成进程常驻内存不退出的运行方式; 2、提供PHP-FPM支持,提高PHP处理速度; 3、支持POST请求; 4、支持文件上传; 原创文章,转载请注明: 转载自始终不够 本文链接地址: 我的第一个github开源项目——Zebra Http Server

shell脚本执行mysql命令

最近因为要修改一张大表的结构,由于不能脱产,所以修改操作只能夜晚进行。又不想熬夜搞太晚,就想用linux的定时任务crontab定时任务来搞定。可以通过管道的方式将SQL语句传送给MYSQL。编写完shell脚本后加入crontab里面,第二天回来搞定了 以下为shell脚本代码: #!/bin/bash qry=<<<eof ALTER TABLE xxx.xxxx ADD ( NAME VARCHAR(50) NOT NULL ); eof echo $qry | mysql -uroot -S /tmp/mysql.sock database 原创文章,转载请注明: 转载自始终不够 本文链接地址: shell脚本执行mysql命令

基于PCNTL的PHP并发编程

基于PCNTL的PHP并发编程

PHP是一门较早出现的WEB开发脚本语言,并由于其语法结构简单、易学、开源等特性迅速占领WEB开发脚本语言领域,并成为这个领域的龙头老大直至今日。PHP从一出生就被设计用来快速开发WEB应用,这也注定了它在某些方面的先天不足,例如在cli环境下处理大量数据的情况,或者在并发编程方面,都显得力不从心。 本文主要讲解基于PCNTL的PHP并发编程,虽然PHP本身不支持多进程,但基于LINUX的PHP扩展PCNTL却可以提供多进程编程。网络上很多同类文章,但笔者进行多次尝试后发现,不是难以控制进程数量,就是有潜在产生僵尸进程或孤儿进程的危险,或者父进程阻塞难以获得更大的并发效果,且大多没有介绍FORK的原理,使得PHP程序员学习PCNTL并发编程尤为困难。本文力求解决这个问题。 FORK编程的大概原理是,每次调用fork函数,操作系统就会产生一个子进程,儿子进程所有的堆栈信息都是原封不动复制父进程的,而在fork之后,父进程与子进程实际上是相互独立的,父子进程不会相互影响。也就是说,fork调用位置之前的所有变量,父进程和子进程是一样的,但fork之后则取决于各自的动作,且数据也是独立的;因为数据已经完整的复制给了子进程。而唯一能够区分父子进程的方法就是判断fork的返回值。如果为0,表示是子进程,如果为正数,表示为父进程,且该正数为子进程的PID(进程号),而如果是-1,表示子进程创建失败。请看如下代码: <?php $pid = pcntl_fork(); switch($pid){ case -1: echo “couldn’t fork”; break; case 0: echo “I’m child”; break; default : echo “I’m parent”; } ?> 以上代码会产生一个子进程,并根据返回的pid进行父子进程的判断。 生产环境中以上代码大多是不适用的,我们需要大量的并发进程为同时为我们处理事情。这时,我们就需要fork多次,而产生的子进程数量需要在我们的控制之中,否则无限制的fork只会拖垮服务器。笔者曾经有过经历,几秒钟服务器负载从0.3左右飙到800多,吓的一身冷汗。 而子进程的使用通常会涉及到两种:子进程执行完任务直接退出;子进程常驻内存,等待任务。以上两种方式适用于不同情况。第一种情况大多我们不需要考虑太多,除非子进程的创建是循环进行的。而第二种则需要考虑进程间通信。 无论哪一种,无可避免的一个问题就是僵尸进程。僵尸进程就是子进程退出后,父进程没有及时回收,系统仍然保留子进程的执行信息(例如PID,退出状态等),留待其他程序读取。如果僵尸进程数量很少,我们可以忽略掉。但如果是在一个循环中fork(并发编程中常见的死循环),这个问题就不能无视了,父进程必须定期回收已经退出的子进程。子进程的回收我们采用pcnt_wait函数来完成。如下面这段代码: <?php while(true){ $pid = pcntl_fork(); switch($pid){ case -1: echo “couldn’t fork”; break; case 0:{ echo “I’m child”; exit(0); } default : $subPid = pcntl_wait($status);
Continue reading 基于PCNTL的PHP并发编程

mysql复制的一例错误:Relay_Log_Pos不变

mysql复制的一例错误:Relay_Log_Pos不变

最近公司的一台Mysql从机延迟了18W秒,两天前发现延迟时,观察SLAVE STATUS,一切正常,以为近期业务调整造成写操作过多,从机延迟的比较厉害,就没有做过多注意。元旦放假回来后发下延迟时间竟然已经有18W。 具体的情况描述如下:IO线程和SQL线程运行正常,master日志拷贝正常。唯一不正常的问题就是Relay_Log_Pos一直不变,且SLAVE STATUS状态并没有报错。以为某一条语句长时间锁住的某张表造成的,但观察processlist发现数据库中并没有任何语句在运行。为了不影响业务运行,我们将所有读操作迁移到了另外一台,并对这台机器进行原因分析。SLAVE STATUS状态如下图: 我们经过几次SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1操作(跳过当前执行位置),发现依然会存在卡住的问题。于是我们想找出卡住的原因,根据上图给出的位置,我们队relay_log进行了分析mysqlbinlog relaylog.008077 –start-position=223496095 -f -d xxx | more 。结果如下图: 我们发现每次卡住的位置都在unkown event事件前面,每次跳过后碰到这个就会卡住。 中继日志中产生这样的时间的原因无从得知,可能是我们调整了表结构分区造成的。 最后我们多次执行SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1操作后不再存在卡住的情况。 原创文章,转载请注明: 转载自始终不够 本文链接地址: mysql复制的一例错误:Relay_Log_Pos不变

初识go语言以及鸭子类型

刚刚接触go语言两天就已经深深的喜欢上了go。写着简单的go代码,好像这就是自己一直在寻找的一门语言。或者我喜欢的不仅仅是这门语言本身,更多的是这门语言简单的编程思想:大道至简。人类一直在寻求将复杂问题简单化的方法,我相信go语言就是这样一门语言。它抛弃了继承机制实现面向对象的很多弊端和繁琐的对象关系,让我们能够集中更多的精力去解决问题。 为什么说go语言相对于其他面向对象语言更加简单。我觉得这得益于鸭子类型的思想。James Whitcomb Riley这样描述鸭子类型:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。刚刚看到这句话很难理解其中深层的含义。鸭子类型并不是第一次接触,通过JS和《七天七语言》的学习,也了解到了鸭子类型的一些思想,但一直不能想通透其中的深层思想。最近看到了一句话,突然觉得这好像就是鸭子类型的精髓:C++等语言实现面向对象的主要方法是继承,而鸭子类型实现面向对象的方式是组合。而我们所熟知的,甚至被奉为面向对象编程原则的”多组合,少继承“的思想也说明了组合要比继承更加灵活方便。 C++中的多继承特性从一定层面反映了开发这想通过更多的父类获得特性;优先组合的思想也反应出我们希望能够使用更多对象的特性并隐藏细节;接口的出现反映出我们不希望通过多继承这样庞大的机制就能够实现更为复杂的对象关系;这些原本都是继承机制的面向对象思想或原则,而我们发现这在go语言中不在是原则,因为go语言一开始就是这样做的。 在日常的面向对象编程过程中,其实也会觉得为了做一个相对完美的抽象,我关注了更多的类之间的关系,而不能把主要精力集中在业务逻辑代码中。一段时间我在考虑是否从PHP转向JAVA,因为PHP在服务器端开发、并发、效率方面真的有点草根(虽然用来编写动态网页是个不错的选择),但最后还是被JAVA庞杂的包给吓到了。由于工作原因而调试一个JAVA程序,就因为各种包的原因迟迟不能有成果,但不能不说JAVA的API真的很规整方便。直到遇到go,并决定开始go。相信自己能够在go编程中真正体验到大道至简的思想。 原创文章,转载请注明: 转载自始终不够 本文链接地址: 初识go语言以及鸭子类型