转载处:https://www.jianshu.com/p/bab74cddcada
“消息中间件”并不是传统LNMP领域中的常见名词,但在一些复杂计算类、耗时类或高负载业务处理时候,通过会采用“队列”的方式进行异步化、计算分布或高峰削平处理,其实这里运用的是“消息中间件”的概念和应用。
应用需求
几种方案简略对比
消息队列中的3个角色
消息队列的解耦
Linux下RabbitMQ的安装&启动
yum -y install erlang rabbitmq-server
service rabbitmq-server start
chkconfig rabbitmq-server on
增加rabbitmq_management(web的监控和管理端)
/usr/lib/rabbitmq/lib/rabbitmq_server-3.1.5/sbin/rabbitmq-plugins enable rabbitmq_management
rabbitMQ服务监听配置
在/etc/rabbitmq 目录下新增文件:rabbitmq-env.conf
RABBITMQ_NODE_IP_ADDRESS=192.168.100.101
RABBITMQ_NODE_PORT=5672
RABBITMQ_NODENAME=rabbit
配置完成,查看端口是否正常监听
service rabbitmq-server restart
netstat -apn | grep 5672
web的监控
监控界面
PHP调用rabbitMQ服务
官方php并没有默认安装开启AMQP相应的扩展,需要单独增加扩展
推荐php-amqplib进行开发,它说明和demo比较齐全,pecl-amqp只是基于amqp协议的扩展,参数和demo几乎没有,不推荐。
worker的处理方式
Yii 2.x下基于php-amqplib 的组件component
题主比较懒,只花了2小时封装了基本的发布、拉取消息的功能,其他功能待封装
namespace frontend\components;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Exception\AMQPConnectionException;
use yii\base\Component;
use PhpAmqpLib\Connection\AMQPConnection;
use PhpAmqpLib\Message\AMQPMessage;
use yii\base\ErrorException;
use yii\base\Event;
use yii\base\Exception;
/**
* Class RabbitMQ
* @package frontend\components
*/
class RabbitMQ extends Component{
const EXCHANGE_TYPE_DIRECT = 'direct';
const EXCHANGE_TYPE_FANOUT = 'fanout';
const EXCHANGE_TYPE_TOPIC = 'topic';
const EXCHANGE_TYPE_HEADER = 'header';
const MESSAGE_DURABLE_YES = 2;
const MESSAGE_DURABLE_NO = 1;
private $_host = '127.0.0.1';
private $_port = 5672;
private $_user = '';
private $_passwd = '';
private $_vHost = '/';
private $_connection = null;
private $_queue = '';
private $_exchange = '';
/**
* 组件初始化
*/
public function init(){
parent::init();
//脚本退出前,关闭连接
register_shutdown_function([$this,'close']);
}
/**
* 连接
*/
public function connect(){
$this->getConnect();
}
/**
* 关闭连接
*/
public function close(){
if($this->_isConnect()){
$this->_connection->close();
}
}
/**
* 设置默认 queue
* @param $queue
*/
public function setDefaultQueue($queue){
$this->_queue = $queue;
}
/**
* 设置默认 exchange
* @param $exchange
*/
public function setDefaultExchange($exchange){
$this->_exchange = $exchange;
}
/**
* 发布消息
* @param $message
* @param $queue
* @param $exchange
* @param bool $passive
* @param bool $durable
* @param bool $exclusive
* @param string $type
* @param bool $auto_delete
* @return bool
*/
public function publishMessage($message,$queue,$exchange,$passive=false,$durable=true,$exclusive=false,$type=self::EXCHANGE_TYPE_DIRECT,$auto_delete=false){
$newChannel = $this->getChannel();
$newQueue = isset($queue)?$queue:$this->_queue;
$newExchange = isset($exchange)?$exchange:$this->_exchange;
if($this->_prepare($newChannel,$newQueue,$newExchange,$passive,$durable,$exclusive,$type,$auto_delete)){
$delivery_mode = ($durable)?self::MESSAGE_DURABLE_YES:self::MESSAGE_DURABLE_NO;
$msg = new AMQPMessage($message, array('content_type' => 'text/plain', 'delivery_mode' => $delivery_mode));
$newChannel->basic_publish($msg,$exchange);
$newChannel->close();
return true;
}
$newChannel->close();
return false;
}
/**
* 拉取消息
* @param $queue
* @param $exchange
* @param bool $passive
* @param bool $durable
* @param bool $exclusive
* @param string $type
* @param bool $auto_delete
* @return bool
*/
public function getMessage($queue,$exchange,$passive=false,$durable=true,$exclusive=false,$type=self::EXCHANGE_TYPE_DIRECT,$auto_delete=false){
$newChannel = $this->getChannel();
$newQueue = isset($queue)?$queue:$this->_queue;
$newExchange = isset($exchange)?$exchange:$this->_exchange;
$mix = false;
if($this->_prepare($newChannel,$newQueue,$newExchange,$passive,$durable,$exclusive,$type,$auto_delete)){
$msg = $newChannel->basic_get($queue);
if($msg){
$newChannel->basic_ack($msg->delivery_info['delivery_tag']);
$mix = $msg->body;
}
}
$newChannel->close();
return $mix;
}
/**
* @return bool
*/
private function _isConnect(){
if($this->_connection && $this->_connection->isConnected()){
return true;
}
return false;
}
/**
* @param $channel
* @param $queue
* @param $exchange
* @param bool $passive
* @param bool $durable
* @param bool $exclusive
* @param string $type
* @param bool $auto_delete
* @return bool
*/
private function _prepare($channel,$queue,$exchange,$passive=false,$durable=true,$exclusive=false,$type=self::EXCHANGE_TYPE_DIRECT,$auto_delete=false){
if($channel && is_a($channel,'\PhpAmqpLib\Channel\AMQPChannel')){
$channel->queue_declare($queue,$passive,$durable,$exclusive,$auto_delete);
$channel->exchange_declare($exchange,$type,$passive,$durable,$auto_delete);
$channel->queue_bind($queue, $exchange);
return true;
}
return false;
}
/**
* @param $host
*/
public function setHost($host){
$this->_host = $host;
}
/**
* @param $port
*/
public function setPort($port){
$this->_port = $port;
}
/**
* @param $user
*/
public function setUser($user){
$this->_user = $user;
}
/**
* @param $passwd
*/
public function setPasswd($passwd){
$this->_passwd = $passwd;
}
/**
* @param $vHost
*/
public function setVHost($vHost){
$this->_vHost = $vHost;
}
/**
* @return AMQPChannel
* @throws ErrorException
*/
public function getChannel(){
return $this->getConnect()->channel();
}
/**
* @return null|AMQPConnection
* @throws ErrorException
* @throws \yii\base\ExitException
*/
public function getConnect(){
if(!$this->_isConnect()){
try{
$this->_connection = new AMQPConnection($this->_host, $this->_port, $this->_user, $this->_passwd, $this->_vHost);
} catch (\PhpAmqpLib\Exception\AMQPRuntimeException $e){
throw new ErrorException('rabbitMQ server connect error',500,1);
}
}
return $this->_connection;
}
}