JAX-RSを使用してRESTAPIを提供するGlassfish3.1.2クラスターにJavaEEアプリケーションをデプロイしています。EARを複製クラスターインスタンスにデプロイすることでアプリケーションの新しいバージョンを定期的にデプロイしてから、HTTPロードバランサーを更新して、古いインスタンスではなく更新されたインスタンスにトラフィックを送信します。
これにより、http://docs.oracle.com/cd/E18930_01/html/821-2426/abdio.html#abdipで説明されているように、可用性を失うことなくアップグレードできます。私たちは頻繁にアプリケーションに大幅な変更を加えているため、新しいバージョンは「互換性がありません」(これが2つのクラスターを使用する理由です)。
ここで、(C ++プロデューサーからの)高スループットの内部メッセージングのために、アプリケーションにメッセージキューインターフェイスを提供する必要があります。ただし、メッセージ駆動型Beanを使用すると、サービスを中断せずにアプリケーションをアップグレードする方法がわかりません。
私が調査したオプションは次のとおりです。
単一のリモートJMSキュー(openMQ)
プロデューサーはメッセージを単一のメッセージキューに送信し、メッセージはMDBによって処理されます。2番目のクラスターインスタンスを開始するとき、メッセージはアップグレードされたクラスターに負荷分散される必要がありますが、「古い」クラスターを停止すると、未処理のトランザクションが失われます。
アップグレード中にJMXを使用してそのメッセージキューへのプロデューサー/コンシューマーを無効にすることを検討しましたが、それはメッセージ配信を一時停止するだけです。古いクラスターを無効にしても、未処理のメッセージは失われます(私は思いますか?)。
また、@ MessageDrivenアノテーションを破棄し、MessageConsumerを手動で作成することも検討しました。これは機能しているように見えますが、MessageConsumerはEJBアノテーションを使用して他のEJBにアクセスできません(私が知る限り)。
// Singleton bean with start()/stop() functions that
// enable/disable message consumption
@Singleton
@Startup
public class ServerControl {
private boolean running=false;
@Resource(lookup = "jms/TopicConnectionFactory")
private TopicConnectionFactory topicConnectionFactory;
@Resource(lookup = "jms/MyTopic")
private Topic topic;
private Connection connection;
private Session session;
private MessageConsumer consumer;
public ServerControl()
{
this.running = false;
}
public void start() throws JMSException {
if( this.running ) return;
connection = topicConnectionFactory.createConnection();
session = dbUpdatesConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
consumer = dbUpdatesSession.createConsumer(topic);
consumer.setMessageListener(new MessageHandler());
// Start the message queue handlers
connection.start();
this.running = true;
}
public void stop() throws JMSException {
if( this.running == false ) return;
// Stop the message queue handlers
consumer.close();
this.running = false;
}
}
// MessageListener has to invoke functions defined in other EJB's
@Stateless
public class MessageHandler implements MessageListener {
@EJB
SomeEjb someEjb; // This is null
public MessageHandler() {
}
@Override
public void onMessage(Message message) {
// This works but someEjb is null unless I
// use the @MessageDriven annotation, but then I
// can't gracefully disconnect from the queue
}
}
各クラスターのローカル/埋め込みJMSキュー
- クライアントは、2つの異なるメッセージキューブローカー(クラスターごとに1つ)に接続する必要があります。
- クラスターインスタンスがダウンしていることをクライアントに通知し、そのブローカーのキューへのメッセージの送信を停止する必要があります。
- 一般に、既存のhttpソリューションよりもはるかに便利で整頓されていません。
代替メッセージキュープロバイダー
- Glassfishを別のタイプのメッセージキューまたは別のベンダー(Apache OpenMQなど)に接続します。おそらく、これらの1つに、特定のコンシューマーのセットからのトラフィックのバランスをとる機能がありますか?
アプリケーションを無効にするだけで、未処理のトランザクションが「強制終了」されると思います。アプリケーションを無効にすると、既存のトランザクションを完了できる場合は、2番目のクラスターを起動した後でそれを実行できます。
どんな助けでもいただければ幸いです!前もって感謝します。