この記事は リクルートライフスタイル Advent Calendar 2017 の14日目の記事です。
はじめに
ホットペッパービューティーでシステム改善を行っている@akechiです。
システム改善の1つとして、RabbitMQの導入を推進しています。
メッセージキューといえば、AWS re:Invent 2017で「Amazon MQ」が発表されました。
Amazon MQの最大の利点は、移行の容易さです。
クラスメソッドさんの記事の通り、エンドポイントを切り替えるだけで移行ができちゃいます。
ただし、これはActiveMQから移行する場合の話です。
では、RabbitMQから移行する場合はどうなるのかを見ていきたいと思います。
RabbitMQでの送受信
まずはじめに、RabbitMQでの送受信の実装を見てみましょう。
一般的な実装方法として、RabbitMQのチュートリアルを参考にします。
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のチュートリアルを参考にします。
送受信の部分に関しては、ほとんど作り変えが必要になりますね。
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と同様、送受信の部分は作り変えが必要になります。
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というサービスを提供する姿勢はやはりすごいなと思いました。