現在、私たちの利用ActiveMQのでは1、いくつかの問題に直面して
- 5.からActiveMQの可用性ベースのレプリケーションleveldbが、ActiveMQのは、すべての更新プログラムのleveldbがもはや存在し、起動しません*
LevelDBストアが廃止されましたとされ 、もはやサポートされない、または使用をお勧めします。推奨店はKahaDBです
が、公式にはKahaDBストレージソリューションをお勧めします、高可用性のためのネイティブサポートはありません。
- 当社の利用leveldbプロセスは、いくつかの奇妙な問題が発生した:キューが消費され、ログがない自動的にクリーンアップを行い、キューだけ削除した後、ログクリーンアップ;手動洗浄後のログを低下させない「スペース使用率」を、ActiveMQのレコードは、あなたがに再起動する必要があります正しい値;「スペース使用率」100%一度は、クラスタが利用できません。人々の公式オンラインAの多くは、同様の問題に言及していないが、彼らはもはやプロセスをサポートしています。
- leveldb延期メッセージをサポートしていません。
- ノードのフェールオーバーが、状況は、全体のクラスタを停止してのみ低下していない後、「スペース使用率を」再起動クリアしますleveldb結局のところleveldbディレクトリ、再初期化し解決するには、(クラスタ全体が1分を服用を中止することが期待されています)
RabbitMQのかrocketmq:これらの理由から、私は新しいコホートプログラムを検討することを提案します。
はじめに2.rocketmq
- ネームサーバー責任を破った自動検出(およびZKでダボ同様の役割);ネームサーバrocketmqでの以前のバージョンでは、直接、そして自分自身を開発するんZKされ、ネームサーバなしの状態は、任意の数のノードになることはできません。
- 生産者クラスタは、n個のノードがアプリケーションのために、クラスタrocketmq主な役割は、ハングproduderプロデューサの後に使用され、他の生産者は、その未処理のトランザクションを継続通知してもよいことが理解されるであろう。
- 消費者クラスタは、また、n個のノードのアプリケーションとして解釈され、それは、n個のコンシューマのロードバランシングを達成することです。
- クラスタは、n番目のマスターとスレーブ破損があってもよい、トピックは、n壊れている可能性があり、n型トピックであってもよいです。
- 壊れ他に、マスターの中で分解した後、マスターが削除されたメッセージの負荷を、しかし、スレーブが壊れ、元はまだ消費者サービスを提供することができます。プロデューサーは、スケールアウト、壊れた負荷分散nは、トピックにメッセージを送信します。
- 異なるRocketmqキューMQなく、特定の論理オブジェクトまたはペアのRabbitMQにActiveMQの生産者と消費者へしかしシャーディングに格納されたメッセージの同時性を高めるために、他の。
- 、デフォルトのノード16で壊れごとに、コンシューマ・キュー番号カスタマイズすることができ、数は消費者の数を超えていなければならない、そうでない場合は、余分な消費がありません。生産者は、各キューをポーリングするには、これらのキューを消費する消費者を負荷分散をメッセージを送信します状況。
- 各メッセージにRocketmqは、待ち行列タグや特定のメッセージをペアリングする生産者と消費者のための他のMQの概念に似特定のタグを追加します。
サンプルコード
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("sina-www");
producer.setNamesrvAddr("10.40.20.200:9876,10.40.20.201:9876");
producer.start();
for (int i = 0; i < 100000; i++) {
Message msg = new Message("topic1", "sina.www.abc", ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
}
producer.shutdown();
}
}
public class Consumer {
public static void main(String[] args) throws InterruptedException, MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("sina-www");
consumer.setNamesrvAddr("10.40.20.200:9876,10.40.20.201:9876");
consumer.subscribe("topic1", "sina.www.abc");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,ConsumeConcurrentlyContext context) {
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
}
}
はじめに3.rabbitmq
- データ交換を提供為替業務と同様のスイッチは、特定のキューにデータを配布します。
- バインディング:交流とキュー間の結合関係、為替の異なる種類、プラスroutekey binging構成を、あなたは、キューの交換や配布ルールの任意の組み合わせを達成することができます。
- 各クラスタ・ノードは、同一の結合と交換情報を有しています。
- 各交換は関係なく、ノード内か否かをマスタ交換、マスターキューメッセージを送信する必要があり、ノードダウン、マスタノードと、マスタキューとスレーブキュー自動同期は、キューは、コピーの数を指定することができる、より少ないノードの数よりもできますキューに対応する他のノードのコピーがマスターにアップグレードされます。
サンプルプログラム
public class Producer {
private static String queueName = "sina.goods.updatestock";
public static void main(String[] args) throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("10.40.20.203");
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName,"lbexchange", queueName);
for (int i = 0; i < 100000; i++) {
String message = "hello world + " + i;
channel.basicPublish("lbexchange", queueName, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
System.out.println(" [x] Sent '" + i + "' ");
}
channel.close();
connection.close();
}
}
public class Consumer {
private static String queueName = "sina.goods.updatestock";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("10.40.20.203");
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(queueName, true, false, false, null);
QueueingConsumer consumer = new QueueingConsumer(channel);
int prefetchCount = 1;
channel.basicQos(prefetchCount);
channel.basicConsume(queueName, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
}
}
}
4.rabbitmq性能試験
因为rocketmq的性能肯定比rabbitmq强,因此只测试了rabbitmq的性能。
测试场景:10个生产者,10个消费者,消费者自动ACK,2节点集群,服务器配置8C8G
压测工具:github.com/rabbitmq/rabbitmq-perf-test
以下分别测试消息大小为10字节和1K、直连主节点和直连从节点,一共4种组合。
消息大小10字节,直连主节点
Cpu 负载:主65%,从25%
消息大小1K,直连主节点
Cpu 负载:主65%,从25%
消息大小10字节,直连从节点
Cpu 负载:主35%,从40%
消息大小1K,直连从节点
Cpu 负载:主30%,从35%
消息积压的表现
关闭消费者,让消息积压,消息大小1K
因为内存限制,消息积压到一定程度要page out到磁盘,因此生产者发送消息会有明显的抖动(page out时会block)。
5.使用总结
Rocketmq
- Rocketmq为高并发海量数据设计,架构很先进,支持容量横向扩展。
- Rocketmq没有我们传统意义上的queue对象,而是通过tag实现消息的分类。消息的负载数据(enqueue\dequeue\pending等)无法精确到tag维度,只能到broken或consumer group。
- 控制台没有包含到原生项目,而是在rocketmq-externals中;控制台更新缓慢,2017年6月第一版后再无新的版本;控制台做得很差
- 没有完全遵守AMQP,只支持java客户端;官方文档简陋。
Rabbitmq
- 一个2节点的集群能保守提供6-7K/S的请求量,性能满足要求(目前我司还没有单个应用队列吞吐超过该数量的请求);
- 准守AMQP 协议,支持多种客户端,如:Python、Ruby、.NET、Java、C、PHP等;
- 控制台很友好,很强大,能看每个queue最近24小时的生产、消费、积压走势图