Edited at

メッセージキューの移行を考えてみる

More than 1 year has passed since last update.

この記事は リクルートライフスタイル Advent Calendar 2017 の14日目の記事です。


はじめに

ホットペッパービューティーでシステム改善を行っている@akechiです。

システム改善の1つとして、RabbitMQの導入を推進しています。

メッセージキューといえば、AWS re:Invent 2017で「Amazon MQ」が発表されました。

Amazon MQの最大の利点は、移行の容易さです。

クラスメソッドさんの記事の通り、エンドポイントを切り替えるだけで移行ができちゃいます。

ただし、これはActiveMQから移行する場合の話です。

では、RabbitMQから移行する場合はどうなるのかを見ていきたいと思います。


RabbitMQでの送受信

まずはじめに、RabbitMQでの送受信の実装を見てみましょう。

一般的な実装方法として、RabbitMQのチュートリアルを参考にします。


RabbitMQSample.java


import com.rabbitmq.client.*;

import java.io.IOException;

public class RabbitMQSample {

private final static String QUEUE_NAME = "testQueue";

public static void main(String[] argv) throws Exception {
// 前処理
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(ホスト名);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();

// メッセージの送信
String message = "Hello World from RabbitMQ!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));

// メッセージの受信
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println("Received '" + message + "'");
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);

// 後処理
channel.close();
connection.close();
}
}



Amazon MQでの送受信

次に、Amazon MQでの送受信の実装を見てみます。

実装方法はAmazon MQのチュートリアルを参考にします。

送受信の部分に関しては、ほとんど作り変えが必要になりますね。


AmazonMQSample.java

package amazon;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

public class AmazonMQSample {

private final static String QUEUE_NAME = "testQueue";

public static void main(String[] args) throws JMSException {

// 前処理
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(エンドポイント);
connectionFactory.setUserName(ユーザ名);
connectionFactory.setPassword(パスワード);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(QUEUE_NAME);

// メッセージの送信
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
String text = "Hello World from Amazon MQ!";
TextMessage producerMessage = session.createTextMessage(text);
producer.send(producerMessage);

// メッセージの受信
MessageConsumer consumer = session.createConsumer(destination);
Message consumerMessage = consumer.receive(1000);
TextMessage consumerTextMessage = (TextMessage) consumerMessage;
System.out.println("Message received: " + consumerTextMessage.getText());

// 後処理
producer.close();
consumer.close();
session.close();
connection.close();
}
}



SQSでの送受信

最後に、SQSでの送受信の実装も見てみましょう。

実装方法はこちらの例を参考にします。

Amazon MQと同様、送受信の部分は作り変えが必要になります。


SQSSample.java

package aws.example.sqs;

import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.AmazonSQSException;
import com.amazonaws.services.sqs.model.CreateQueueResult;
import com.amazonaws.services.sqs.model.Message;
import com.amazonaws.services.sqs.model.SendMessageBatchRequest;
import com.amazonaws.services.sqs.model.SendMessageBatchRequestEntry;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import java.util.Date;
import java.util.List;

public class SQSSample {

private final static String QUEUE_NAME = "testQueue";

public static void main(String[] args) {
// 前処理
final AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();
String queueUrl = sqs.getQueueUrl(QUEUE_NAME).getQueueUrl();

// メッセージの送信
SendMessageRequest send_msg_request = new SendMessageRequest()
.withQueueUrl(queueUrl)
.withMessageBody("Hello World from SQS!")
.withDelaySeconds(5);
sqs.sendMessage(send_msg_request);

// メッセージの受信
List<Message> messages = sqs.receiveMessage(queueUrl).getMessages();
for (Message m : messages) {
System.out.println("Message received: " + m.getBody());
sqs.deleteMessage(queueUrl, m.getReceiptHandle());
}
}
}



移行の比較

RabbitMQからの移行コスト(実装)は、Amazon MQとSQSでほとんど同じだと思います。

ただ、移行して得られることはそれぞれ異なります。

移行
得られること

RabbitMQ -> Amazon MQ
運用工数の削減、可用性と耐久性

RabbitMQ -> SQS
(上記に加えて)スケーラビリティ


おわりに

現時点では、RabbitMQから移行を考えた場合SQSの方が良いのかなと思います。

ただ、Amazon MQがActiveMQしかサポートしていない今の話で、今後RabbitMQをサポートするとまた話が変わってきますし、十分に考えられる未来だと思っています。

いづれにせよ変わらないことは、最終的にはSQSを使ったシステムに移行していくことがベストだということです。

Amazon MQとSQSの違いは以下のように記載されています。(引用元:https://docs.aws.amazon.com/ja_jp/amazon-mq/latest/developer-guide/welcome.html


Amazon MQ は Amazon SQS や Amazon SNS とはどう違うのですか?

Amazon MQ はマネージド型メッセージブローカーサービスであり、多くの一般的なメッセージブローカーと互換性があります。API (JMS など) や、プロトコル (AMQP、MQTT、OpenWire、Stomp など) との互換性に依存する既存のメッセージブローカーからのアプリケーション移行に Amazon MQ をお勧めします。

Amazon SQS および Amazon SNS はキューおよびトピックサービスであり、高度にスケーラブルでシンプルに使用でき、メッセージブローカーを管理する必要がありません。新規のアプリケーションには Amazon SQS および Amazon SNS をお勧めします。ほぼ無制限の拡張性とシンプルな管理がメリットです。


SQSという強力なメッセージキューサービスを展開しながら、顧客がSQSへの移行に困っていることに課題を感じ、新たにAmazon MQというサービスを提供する姿勢はやはりすごいなと思いました。