ActiveMQ 简述
ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。
ActiveMQ 采用消息推送方式,所以最适合的场景是默认消息都可在短时间内被消费。数据量越大,查找和消费消息就越慢,消息积压程度与消息速度成反比。
消息中间件
消息中间件
是值利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型
,可以在分布式架构下扩展进程之间的通信。
消息中间件主要解决的就是分布式系统之间消息传递的问题
,它能够屏蔽各种平台以及协议之间的特性,实现应用程序之间的协同。
分布式消息队列的第一个解决场景【异步处理】
消息队列的方式可以很好的缓解高流量的问题
在弱一致性事务模型中,可以采用分布式消息队列的实现最大能力通知方式来实现数据的最终一致性
安装前置
java包支持
sudo apt-get install openjdk-7-jdk
// Ubuntu16.04的安装源已经默认没有openjdk7了,所以要自己手动添加仓库
sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-7-jdk // OpenJdk 7安装
安装 ActiveMQ
官网下载安装包 `http://activemq.apache.org/download.html`
解压进入文件执行初始化:
tar -zxvf apache-activeMQ.tar.gz
bin/activemq setup /etc/default/activemq
启动方式:
普通启动 sh activemq start
启动并指定日志 sh activemq start > /tmp/activemqlog
控制台启动 sh activemq console
检查启动:
ActiveMQ默认采用 61616 端口提供 JMS服务,使用 8161端口提供管理控制台服务,执行以下命令可以检查是否成功启动 ActiveMQ 服务
netstat -an|grep 61616
检查进程存在: ps -aux | grep mq
默认管理页面: http://localhost:8161
账号密码:admin admin 可以查看现在mq队列处理情况,用户名密码是在conf/users.properties中配置
消息生产
现在比较方便的操作使用stomp协议实现mq队列 ,项目中要加载stomp 包
use App\Libraries\Stomp\Stomp;
将消息放入 MQ 队列:
protected function sendToMQ($destination, $msg_data, $persistent = false)
{
try {
$con = new Stomp(config('app.mq_url'));
$con->connect();
$con->begin("Transaction");
$con->send($destination, json_encode($msg_data), array('persistent'=> $persistent));
$con->commit("Transaction");
$con->disconnect();
} catch (\Exception $e) {
app('log')->warn($e->getMessage());
}
}
/*
1.destination是指队列名称;
2.msg_data队列中存放的数据;
3.persistent是否同步;
4.app.mq_url是指activeMq安装的服务器地址及端口号,如tcp://localhost:61613;
经过段代码之后,我们就将数据msg_data放到了队列destination中了;
*/
队列消费
try {
$this->consumer = new Stomp($this->activemq_uri); //$this->acitvemq_uri就是上面的activeMq地址app.mq_url
if (!$this->consumer->isConnected()) {
$this->consumer->connect();
$this->consumer->setReadTimeout(3);
}
app('log')->info($this->log_remark . "connect to active mq success");
} catch (StompException $e) {
app('log')->info("connect to active mq failed : " . $e->getMessage());
die();
}
$queue = self::getQueue();//得到队列名称,上面定义的destination
$this->consumer->subscribe($queue); //订阅
//循环读帧
while ($this->consumer->hasFrameToRead()) {
try {
$message = $this->consumer->readFrame();
$data = json_decode($message->body, true); // 这里其实就是得到了上面的队列消息msg_data
//验证数据并更新数据
$handle_result = self::removeDuplicateExpressInfo($data['traces'], $data['shipping_id']);
if ($handle_result) {
$this->consumer->ack($message);
}
} catch (\Exception $e) {
app('log')->info("handle with message failed : " . $e->getMessage());
if (!$this->consumer->isConnected()) {
$this->consumer->connect();
} else {
break;
}
}
}
$this->consumer->unsubscribe($queue); //释放订阅
$this->consumer->disconnect(); //端口连接
缺点
吞吐量低
由于 ActiveMQ 需要建立索引,导致吞吐量下降。这是无法克服的缺点,只要使用完全符合 JMS 规范的消息中间件,就要接受这个级别的TPS。无分片功能
。这是一个功能缺失,JMS 并没有规定消息中间件的集群、分片机制。而由于 ActiveMQ 是伟企业级开发设计的消息中间件,初衷并不是为了处理海量消息和高并发请求。如果一台服务器不能承受更多消息,则需要横向拆分。ActiveMQ 官方不提供分片机制,需要自己实现。
适用场景
对 TPS 要求比较低的系统
,可以使用 ActiveMQ 来实现,一方面比较简单,能够快速上手开发,另一方面可控性也比较好,还有比较好的监控机制和界面
不适用场景
消息量巨大的场景
。ActiveMQ 不支持消息自动分片机制,如果消息量巨大,导致一台服务器不能处理全部消息,就需要自己开发消息分片功能。