web-dev-qa-db-ja.com

この場合、Webサービスは必要ですか?複数のクライアントでのデータ同期

私はこの分野の初心者で、アプリケーションのWebサービス実装に関する現在の考えについて少し混乱しています。接続されているすべてのクライアントをMySQL DB上の現在のデータと同期させたい。調整の目的でWebサービスを使用するようになりましたが、行き詰まりました。

私がそれを実装しようとした方法は...

Webサービスがデーモンを実行して、DBデータに影響を与えるCRUD操作をチェック/リッスンします。 CRUD操作が発生すると、接続されているすべてのクライアントへの通知が確実に解除され、各クライアントが現在のDBデータでJTableを更新し、DBで行われた変更をユーザーに通知します。

これは私が行き詰まっているところです...

概念的にはWebサービスがクライアントの要求を待ってから、対応する応答を送信するため、私はそれが(たぶん?)間違っていると考えています。しかし、ここではクライアントのリクエストはありません。 Webサービスは、応答(通知)を送信するだけです。これは、「呼び出し元」のクライアントを認識していないため、マルチキャストする必要があります。要求はありません。

したがって、DBで変更が発生した場合、クライアントがリクエストを送信するには、常にWebサービスを「cron」にする必要があります。次に、Webサービスは、CRUD詳細(CRUDEventFired(event_type、event_details))でtrueまたはfalseとして応答します。ただし、特にCRUD操作が発生していない場合は、大きくて(ほとんどの場合)無駄なトラフィックが発生するため、これは最適ではありません。また、同じタイプのイベントをチェック/リッスンする2つの異なるデーモン(1つはWebサービスにあり、もう1つはクライアントアプリにあります)があり、それは冗長です。

また、その実装では、Webサービスはまったく必要ないようで、変更をDBで確認するコードをクライアントで実装できます。一方、DBの変更を担当するクライアントを設定するには、異なるプラットフォーム(デスクトップ、iOS、Androidなど)で同じ機能をコーディングする必要がありますが、クライアント間のデータ同期のコーディネーターとしてWebサービスを設定すると、コーディングが必要になります。適切な関数と各クライアントが一度だけ独自のNotificationListener()を実装するだけです。

私がWebサービスを使用して考えている方法は間違っていますか?どのように変更する必要がありますか? Webサービスも使用する必要がありますか?

あなたの便宜のために図を添付します。

diagram

3
John Astralidis

私は専門家ではありませんが、ここに私の2セントがあります。私はあなたのウェブサービスがJava EEアプリケーションサーバーで実行されていると思います。

  • dBへの書き込みはすべてアプリケーションサーバーから行う必要があるため、DBに書き込むたびにコード内でイベントを生成できるはずです。
  • クライアントからのクエリに最適なWeb​​サービスの代わりに、Webソケットまたはメッセージキュー(通常はJMSキュー)を使用できます。

クライアントにDBに直接書き込むことは、最初は魅力的に思えるかもしれませんが(理解しやすい)、すぐに混乱する可能性があります。たとえば、今後DBに変更を加える場合は、すべてのクライアントをアップグレードする必要があります。

1
assylias

バックエンドサービスから各フロントエンドクライアントにプッシュ通知を実装しようとしているようです。

2つのオプションが思い浮かびます:

  1. WebSocketsを使用すると、クライアントはサーバーとの永続的な双方向通信チャネルを維持できます。クライアント上の更新は永続チャネルに沿って送信でき、Webサーバーがデータストアへの変更を受信すると、接続されている各クライアントに変更を伝播できます。これを使用すると、各クライアントはおそらく(これについては後で詳しく説明します)、変更を加えたいときにいつでも最も更新されたデータを持っている

  2. HTTP Long Pollは、長いタイムアウトを使用してHTTPを利用し、Push更新に似たものを実行する古い方法(非常にうまく機能します)です。各クライアントは、あるリソースに対してHTTPリクエストを開き、タイムアウトが長くなります(たとえば、2分)。何かが変更されると、サーバーは新しいデータで応答します。それ以外の場合は、サーバーに304 NOT MODIFIED応答を送信する前に2分間待機します。このようにして、クライアントは通知をすぐに取得できますが、常にポーリングする必要はありません。

これらのアイデアはどちらもここで読むことができます: https://en.wikipedia.org/wiki/Push_technology#HTTP_server_Push

これらのオプションはどちらも、2つのクライアントが同時に更新を行い、一方が他方を上書きする可能性があるという問題があります。このように、データストアが同期しなくなったり、論理的に矛盾したりするのは簡単です。これを避けたい場合は、pjc50で述べたように、分散データベースの使用を検討してください。

それが便利だと思う人のために、ここにロングポーリングのためのいくつかの疑似コードがあります:

long-pollクライアント&サーバー疑似コード

/**
 * Handles long-poll request for one client and sends updated
 * content to the client when it changes, or a 304 NOT MODIFIED
 * response if it doesn't change within the timeout period
 */

handleClientRequest(HTTRequest clientRequest) {
    String uri = clientRequest.getURI();
    int timeout = clientRequest.getTimeout();

    /* Wait for the resource to change. You should use
     * a more sophisticated waiting scheme, like semaphores,
     * Java monitors, or any number of thread synchronization
     * techniques
     */
    while ((resource hasnt changed) && (total wait time < timeout))
        sleep(timeout / 100)

    if (resource did change)
        send new content
    else
        send HTTP 304 NOT MODIFIED response
}

/**
 * Continually sends long-poll requests to the server,
 * and updates data whenever it changes
 */
clientLongPoll(uri) {
    int timeout = 120 // seconds

    while (true) {
        HttpRequest request = new Request(uri);
        request.setTimeout(timeout);

        /* this will hang until the server responds, up to 2 minutes */
        HttpResponse response = request.send()  
        if (resposne.contentChanged() == true)
            update local data store
    }
}

Webソケットライブラリは通常、イベントベースのスキーム(onConnected()、onNewMessage()、onDisconnected()など)に依存しますが、各ライブラリは異なります。基本的な考え方は、クライアントが起動するときはいつでも、サーバーに接続してWebSocket接続を開始し、そこからローカルデータが変更されるたびにメッセージを送受信できるというものです。

3
nmio