多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
vhosts : 虚拟主机。 一个RabbitMQ的实体上可以有多个vhosts,用户与权限设置就是依附于vhosts。对一般PHP应用,不需要用户权限设定,直接使用默认就存在的”/”就可以了,用户可以使用默认就存在的”guest”。一个简单的配置示例: $conn_args = array( 'host' => '127.0.0.1', 'port' => '5672', 'login' => 'guest', 'password' => 'guest', 'vhost'=>'/' ); connection 与 channel : 连接与信道 connection是指物理的连接,一个client与一个server之间有一个连接;一个连接上可以建立多个channel,可以理解为逻辑上的连接。一般应用的情况下,有一个channel就够用了,不需要创建更多的channel。示例代码: //创建连接和channel $conn = new AMQPConnection($conn_args); if (!$conn->connect()) { die("Cannot connect to the broker!\n"); } $channel = new AMQPChannel($conn); exchange 与 routingkey : 交换机与路由键 为了将不同类型的消息进行区分,设置了交换机与路由两个概念。比如,将A类型的消息发送到名为‘C1’的交换机,将类型为B的发送到’C2’的交换机。当客户端连接C1处理队列消息时,取到的就只是A类型消息。进一步的,如果A类型消息也非常多,需要进一步细化区分,比如某个客户端只处理A类型消息中针对K用户的消息,routingkey就是来做这个用途的。 $e_name = 'e_linvo'; //交换机名 $k_route = array(0=> 'key_1', 1=> 'key_2'); //路由key //创建交换机 $ex = new AMQPExchange($channel); $ex->setName($e_name); $ex->setType(AMQP_EX_TYPE_DIRECT); //direct类型 $ex->setFlags(AMQP_DURABLE); //持久化 echo "Exchange Status:".$ex->declare()."\n"; for($i=0; $i<5; ++$i){ echo "Send Message:".$ex->publish($message . date('H:i:s'), $k_route[i%2])."\n"; } 对于交换机,有两个重要的概念: A、类型。有三种类型: Fanout类型最简单,这种模型忽略routingkey; Direct类型是使用最多的,使用确定的routingkey。这种模型下,接收消息时绑定’key_1’则只接收key_1的消息; 最后一种是Topic,这种模式与Direct类似,但是支持通配符进行匹配,比如: ‘key_*’,就会接受key_1和key_2。Topic貌似美好,但是有可能导致不严谨,所以还是推荐使用Direct。 B、持久化。指定了持久化的交换机,在重新启动时才能重建,否则需要客户端重新声明生成才行。 需要特别明确的概念:交换机的持久化,并不等于消息的持久化。只有在持久化队列中的消息,才能持久化;如果没有队列,消息是没有地方存储的;消息本身在投递时也有一个持久化标志的,PHP中默认投递到持久化交换机就是持久的消息,不用特别指定。 $e_name = 'e_linvo'; //交换机名 $q_name = 'q_linvo'; //队列名 $k_route = ''; //路由key //创建连接和channel $conn = new AMQPConnection($conn_args); if (!$conn->connect()) { die("Cannot connect to the broker!\n"); } $channel = new AMQPChannel($conn); //创建交换机 $ex = new AMQPExchange($channel); $ex->setName($e_name); $ex->setType(AMQP_EX_TYPE_DIRECT); //direct类型 $ex->setFlags(AMQP_DURABLE); //持久化 echo "Exchange Status:".$ex->declare()."\n"; //创建队列 $q = new AMQPQueue($channel); $q->setName($q_name); $q->setFlags(AMQP_DURABLE); //持久化 //绑定交换机与队列,并指定路由键 echo 'Queue Bind: '.$q->bind($e_name, $k_route)."\n"; //阻塞模式接收消息 echo "Message:\n"; $q->consume('processMessage', AMQP_AUTOACK); //自动ACK应答 $conn->disconnect(); /** * 消费回调函数 * 处理消息 */ function processMessage($envelope, $queue) { var_dump($envelope->getRoutingKey); $msg = $envelope->getBody(); echo $msg."\n"; //处理消息 } 从上述示例中可以看到,交换机既可以由消息发送端创建,也可以由消息消费者创建。 创建一个队列(line:20)后,需要将队列绑定到交换机上(line:25)队列才能工作,routingkey也是在这里指定的。有的资料上写成bindingkey,其实一回事儿,弄两个名词反倒容易混淆。 消息的处理,是有两种方式: A,一次性。用 $q->get([…]),不管取到取不到消息都会立即返回,一般情况下使用轮询处理消息队列就要用这种方式; B,阻塞。用 $q->consum( callback, […] ) 程序会进入持续侦听状态,每收到一个消息就会调用callback指定的函数一次,直到某个callback函数返回FALSE才结束。 流控机制 当消息生产的速度更快,而进程的处理能力低时,消息就会堆积起来,占用内存越来越多,导致MQ崩溃,所以rabbitmq有一个流控机制,当超过限定时候就会阻止接受消息,mq流控有三种机制 1,主动阻塞住发消息太快的连接,这个无法调整,如果被阻塞了,在abbitmqctl 控制台上会显示一个blocked的状态。 2,内存超过限量,会阻塞连接,在vm_memory_high_watermark可调 3,剩余磁盘在限定以下mq会 主动阻塞所有的生产者,默认为50m,在disk_free_limit可调.