分散IM(インスタントメッセージング)システムを自分で構築する

分散IM(インスタントメッセージング)システムを自分で構築する

以前、「*** のメッセージ プッシュ システムの設計」という記事を共有しました。記事にはいくつかの疑似コードが掲載されていますが、実行可能なソースコードを直接共有したいと考えている友人もいます。長い間経ちましたので、その穴を埋める時が来ました。

そこで、以前の内容に基づいていくつかの内容を改善しました。このプロジェクトの紹介を見てみましょう。CIM (CROSS-IM) は開発者向けの IM (インスタント メッセージング) システムです。また、開発者が独自の水平スケーラブルな IM を構築するのに役立つコンポーネントもいくつか提供します。

CIM を使用すると、次の要件を実現できます。

  • IM インスタント メッセージング システム。
  • アプリ用のメッセージ プッシュ ミドルウェア。
  • IoT 大量接続シナリオにおけるメッセージ透過伝送ミドルウェア。

完全なソースコードは GitHub でホストされています:

  1. https://github.com/crossoverJie/cim

今回は主に IM インスタント メッセージングに関するものなので、特別に 2 つのビデオ デモ (グループ チャットとプライベート チャット) を録画しました。

グループチャット

プライベートチャット

建築デザイン

具体的なアーキテクチャ設計を見てみましょう。

  • CIM の各コンポーネントは Spring Boot を使用して構築されます。
  • 基盤となる通信を構築するには、Netty + Google Protocol Buffer が使用されます。
  • Redis は各クライアントのルーティング情報、アカウント情報、オンライン ステータスなどを保存します。
  • Zookeeper は、IM サーバー サービスの登録と検出に使用されます。

システム全体は主に以下のモジュールで構成されています。

  • cim-server、IM サーバー: クライアント接続の受信、メッセージの透過的な送信、メッセージのプッシュなどの機能に使用されます。クラスターの展開をサポートします。
  • cim-forward-route、メッセージ ルーティング サーバー: メッセージ ルーティング、メッセージ転送、ユーザー ログイン、ユーザー オフライン、およびいくつかの操作ツール (オンライン ユーザー数の取得など) を処理するために使用されます。
  • cim-client、IM クライアント: 1 つのコマンドで起動して他のユーザーと通信 (グループ チャット、プライベート チャット) できるユーザー用のメッセージング ターミナル。よく使用されるコマンドがいくつか組み込まれており、簡単に使用できます。

フローチャート

全体的なプロセスは比較的単純で、フローチャートは次のとおりです。

  • クライアントはルートへのログインを開始します。
  • ログインが成功すると、Zookeeper から利用可能な im-server が選択されてクライアントに返され、ログイン情報とルーティング情報が Redis に保存されます。
  • クライアントは IM サーバーへの長い接続を開始し、成功した後ハートビートを維持します。
  • クライアントがオフラインになると、ステータス情報は Route を通じてクリアされます。

したがって、自分でデプロイする場合は、次の手順に従う必要があります。

  • 基本的なミドルウェア Redis と Zookeeper を構築します。
  • 実際の IM サーバーである cim-server をデプロイします。パフォーマンス要件を満たすために、水平拡張をサポートしており、同じ Zookeeper に登録するだけで済みます。
  • ルーティング サーバーである cim-forward-route をデプロイし、すべてのメッセージがそれを通過する必要があります。ステートレスなので、可用性を向上させるために Nginx プロキシとして使用することもできます。
  • cim-client は真のユーザー指向クライアントです。起動後、自動的に IM サーバーに接続し、コンソールでメッセージを送受信できるようになります。

詳しい使用方法については、クイックスタートを参照してください。

詳細設計

次に、グループチャットやプライベートチャットのメッセージの流れなど、具体的な実装に焦点を当てます。 IM サーバーの負荷分散。サービスが登録および検出される方法など。

IM サーバー

まずサーバーを見てみましょう。主にクライアントのオンラインとオフライン、メッセージ送信などの機能を実装します。

まず、サービスを開始します。

Spring Boot で構築されているため、アプリケーションの起動時に Netty サービスを開始する必要があります。

Pipline からは、Protobuf エンコードとデコードが使用されていることがわかります (特定のメッセージがクライアントで分析されます)。

登録の検出

IM サーバーの水平拡張要件を満たす必要があるため、cim-server は独自のデータを登録センターに公開する必要があります。

したがって、アプリケーションが正常に起動した後、そのアプリケーション独自のデータを Zookeeper に登録する必要があります。

主な目的は、現在のアプリケーションの IP + CIM サーバー ポート + http ポートを登録することです。

上の図は、デモ環境に登録された 2 つの cim-server インスタンスを示しています (同じサーバー上にあるため、ポートのみが異なります)。

このようにして、クライアント(この Zookeeper ノードをリッスンしている)は、現在利用可能なサービス情報をリアルタイムで知ることができます。

ログイン

クライアントが cim-forward-route のログイン インターフェイスを要求し (詳細は下記を参照)、ビジネス検証を完了すると (日常的に他の Web サイトにログインする場合と同様に)、前のプロセスで示したように、クライアントはサーバーへの長い接続を開始します。

このとき、クライアントは現在の情報がログイン情報であることを示す特別なメッセージを送信します。メッセージを受信した後、サーバーはクライアントのユーザー ID と現在のチャネル関係を保存する必要があります。

また、ユーザーID とユーザー名などのユーザー情報もキャッシュします。

オフライン

クライアントが切断された場合、キャッシュされた情報もクリアする必要があります。

同時に、関連情報をクリアするために Route インターフェースを呼び出す必要もあります (具体的なインターフェースについては以下を参照してください)。

IMルーティング

アーキテクチャ図からわかるように、ルーティング層は非常に重要なリンクです。クライアントとサーバーを接続するための一連の HTTP サービスを提供します。現在、主なインターフェースは次のとおりです。

①登録インターフェース

各クライアントは使用する前にログインする必要があるため、最初のステップは当然登録です。

ここでの設計は比較的シンプルで、Redis を直接使用してユーザー情報を保存します。ユーザー情報にはIDとユーザー名のみが含まれます。

クエリを容易にするために、Redis の KV は VK を順番に保存するため、ID と userName の両方が一意である必要があります。

②ログインインターフェース

ここでのログインは cim-server のログインとは異なり、ビジネス上の性質を持ちます。

  • ログインが成功した後、それが繰り返しのログインであるかどうかを判断する必要があります (ユーザーは 1 つのクライアントしか実行できません)。
  • ログインに成功したら、Zookeeper からサービス リスト (cim-server) を取得し、特定のアルゴリズムに基づいてサービスを選択してクライアントに返す必要があります。
  • ログインに成功したら、ルーティング情報、つまり現在のユーザーに割り当てられたサービスインスタンスを Redis に保存する必要もあります。

1 人のユーザーだけがログインできるようにするために、Redis の Set を使用してログイン情報を保存します。 userID をキーとして使用すると、重複したログインの書き込みは失敗します。

Java の HashSet と同様に、重複のないデータのみを保存できます。

利用可能なルーティング インスタンスを取得することも比較的簡単です。

  • まず、Zookeeper からすべてのサービス インスタンスを取得して内部キャッシュを作成します。
  • サーバーを選択するためのポーリング (現在はこのアルゴリズムのみが存在し、後で新しいアルゴリズムが追加される予定です)。

もちろん、Zookeeper でサービス インスタンスを取得する前に、cim-server が以前に登録したノードをリッスンする必要があります。

具体的なコードは次のとおりです。

また、アプリケーションの起動後に Zookeeper 内のルーティング ノードを監視し、変更が発生すると内部キャッシュを更新します。

ここでは、Concurrent HashMap に基づく Guava のキャッシュが使用されているため、キャッシュのクリアと追加の原子性が保証されます。

③グループチャットインターフェース

これは実際のメッセージ送信インターフェースです。その結果、1 つのクライアントがメッセージを送信すると、他のすべてのクライアントがそのメッセージを受信できるようになります。

プロセスは、クライアントがサーバーにメッセージを送信することです。サーバーはそれを受信すると、上で紹介した SessionSocketHolder 内のすべてのチャネルをトラバースし、メッセージを送信します。

サーバーは単一のマシンでも構いませんが、現在はクラスター設計になっています。したがって、すべてのクライアントは、以前のポーリング アルゴリズムに従って、異なる cim-server インスタンスに割り当てられます。

したがって、ルーティング層が次のような役割を果たす必要があります。

メッセージを受信した後、ルーティング インターフェイスはまずすべてのクライアントとサービス インスタンス間の関係を走査します。ルーティング関係は次のように Redis に保存されます。

Redis はシングルスレッドであるため、データ量が多い場合は、すべての cim-route:* データと一致するように Keys が使用されると、Redis は他のリクエストを処理できなくなります。

したがって、ここでは Scan コマンドを使用してすべての cim-route:* を走査します。次に、各クライアントが配置されているサーバーの HTTP インターフェースが 1 つずつ呼び出され、メッセージがプッシュされます。

cim-server での実装は次のとおりです。

メッセージを受信した後、cim-server はユーザー ID のチャネルの内部キャッシュを照会し、メッセージを送信します。

④オンラインユーザーインターフェース

これは、現在のオンライン ユーザー情報を照会できる補助インターフェイスです。

実装も非常にシンプルで、以前に「ユーザー ログイン ステータス」を保存したものを照会してリセットするだけです。

⑤プライベートチャットインターフェース

オンラインユーザーを取得することが補助的なインターフェースである理由は、実際にはプライベートチャットを支援するために使用されるためです。

一般的に、プライベート チャットを使用する前に、現在オンラインになっているユーザーを把握する必要があります。そうすれば、誰とプライベート チャットをしたいかがわかります。

次のようなものです:

このシナリオでは、プライベート チャットの前提条件は、オンライン ユーザーのユーザー ID を取得することです。

したがって、メッセージを受信した後、プライベート チャット インターフェイスは受信者がいる cim-server インスタンス情報を照会する必要があり、その後の手順はグループ チャットと同じです。情報を送信するには、受信者が配置されているインスタンスの HTTP インターフェイスを呼び出します。

唯一の違いは、グループ チャットはすべてのオンライン ユーザーに送信されるのに対し、プライベート チャットは 1 人のユーザーにのみ送信されることです。

⑥オフラインインターフェース

クライアントがオフラインになると、Redis に以前保存された一部の情報 (ルーティング情報、ログイン ステータス) を削除する必要があります。

IM クライアント

クライアント内のロジックの一部については、実際に上記で説明しました。

ログイン

最初のステップはログインです。起動時に Route のログイン インターフェイスを呼び出して、cim-server 情報を取得し、接続を作成する必要があります。

ログイン プロセス中に、ルート インターフェイスは繰り返しログインかどうかを判断します。繰り返しログインした場合は、プログラムはそのまま終了します。

次のステップは、ルート インターフェイスによって返される cim-server インスタンス情報 (ip+port) を使用して接続を作成することです。

最初のステップは、クライアントとチャネル間の関係を維持できるように、サーバーにログイン メッセージを送信することです。

カスタムプロトコル

上記のログイン メッセージと実際のメッセージは、カスタム プロトコルで区別できます。

エンコードとデコードには Google Protocol Buffer が使用されるので、まずは元の形式を見てみましょう。

実際、このプロトコルには現在 3 つのフィールドがあります。

  • requestId は userId として理解できます。
  • reqMsg は実際のメッセージです。
  • type は上記のメッセージ カテゴリです。

現在、さまざまなビジネスに対応する 3 つの主要なタイプがあります。

ハートビート

クライアントとサーバー間の接続を維持するために、メッセージが送信されていない場合は、ハートビートを定期的に自動的に送信する必要があります。

現在の戦略は、1 分ごとにハートビート パケットをサーバーに送信することです。

この方法では、サーバーはビジネス メッセージを受信しない場合、1 分ごとに Ping ハートビート パケットを受信します。

組み込みコマンド

クライアントには、使いやすさを考慮していくつかの基本的なコマンドも組み込まれています。

たとえば、:q と入力すると、クライアントが終了し、一部のシステム リソースがシャットダウンされます。

:olu (onlineUser の略) を入力すると、ルートが呼び出され、すべてのオンライン ユーザー インターフェイスが取得されます。

グループチャット

グループチャットの使い方はとても簡単です。コンソールにメッセージを入力して Enter キーを押すだけです。このとき、Route のグループ チャット インターフェイスが呼び出されます。

プライベートチャット

プライベート チャットでも同様ですが、前提条件としてキーワードをトリガーする必要があります。ユーザーIDを使用します。この形式のメッセージ コンテンツは特定のユーザーにメッセージを送信するために使用されるため、通常は、便利に使用する前に :olu コマンドを使用してすべてのオンライン ユーザーを取得する必要があります。

メッセージコールバック

メッセージの保存の必要性など、いくつかのカスタマイズされた要件を満たすため。したがって、クライアントはメッセージを受信した後、実装をカスタマイズできるインターフェースをコールバックします。

したがって、最初に Caller Bean が作成されます。この Bean には CustomMsgHandleListener インターフェースが含まれています。自分で処理する必要がある場合は、このインターフェースを実装するだけで済みます。

インターフェースをカスタマイズする

私はインターフェースを書くのがあまり得意ではないので、インターフェースを書くことができる他の専門家がいると確信しています。したがって、グループ チャット、プライベート チャット、オンライン ユーザー獲得、メッセージ コールバック、およびクライアント内のその他のサービス (および後続のサービス) はすべて、インターフェイスの形式で提供されます。

後からページを統合する場合にも便利です。これらのインターフェースを調整するだけで済みます。具体的な実装について心配する必要はありません。

要約する

Cim は現在最新バージョンに過ぎず、バグが多く、機能も少ないです (テストを行うよう招待されたのは数人のグループ メンバーだけです)。ただし、後で改善される予定です。少なくともこのバージョンは、関連する経験がない友人にいくつかのアイデアをもたらすでしょう。

次のステップ:

<<:  rust-vmm で未来の仮想化アーキテクチャを構築する

>>:  10年ぶりのアリババクラウドの新たなスタートを理解する

推薦する

本日より動画のプロモーションも開始いたします。

ビデオプロモーションは、最も早く海外で始まりました。基本的にはショッピングモールのウェブサイトを宣伝...

Python で大きなファイルを読み取る

1. はじめに数日前、ログ解析システムに取り組んでいて、数十 GB のファイルを処理する必要がありま...

HP、1TBのストレージスペースを無料でアップグレード

HP は PC クライアントに最大 1TB の無料ストレージ スペースを提供しており、データの保存や...

2019 年のサーバーレス テクノロジーに関する 5 つの予測

クラウドコンピューティング技術が今後さらに影響力を増すにつれ、サーバーレスの開発は継続されます。 2...

Kubernetes Podの排除に関する詳細な説明

Kubernetes Pod が削除されるとはどういう意味ですか?これらは通常、リソース不足のために...

キーワードランキングはあるがトラフィックやユーザー数がない場合の対処法

多くのウェブマスターは、ランキングが上がったのにトラフィックがないのはなぜかと尋ねたがります。キーワ...

タオバオの顧客は自分自身と敵を知っているので、どんな戦いにも勝つことができる

2010年以来、Taobao Affiliates がインターネット上に静かに登場してきました。今で...

Q&A: CDN テクノロジーがサイト SEO に与える影響の 3 つの側面

インターネットの発展は**スタイルであり、テクノロジーは常に革新を続けていると言えます。ウェブアプリ...

データセンターの華氏68度という温度制限は過去のものとなった。仮想化によりサーバーが沸騰します。

[51CTO.com 6月18日海外ニュースの見出しの速報] データセンターを68度に冷却するのはす...

ブランドプロモーションにWeChatマーケティングを活用する方法

WeChatは、70年代、80年代、90年代に生まれた人にとってはよく聞く言葉だと思います。信憑性は...

Vaicdn: バックアップ CDN は不要、帯域幅が広く、防御力が高く、アジア太平洋地域のノードが多数あり、攻撃によるレイテンシへの影響がない

プロフェッショナルな CDN プロバイダーである Vaicdn は、常に大きな帯域幅、高い防御力、低...

6月の世界ウェブサーバー市場シェア:マイクロソフトの36.35%がApacheに迫る

IDC Review Network (idcps.com) は 6 月 11 日に次のように報告し...

Baidu アルゴリズムのアップグレード後にかつて人気だった SEO ソフトウェアを確認する方法

ソフトウェアは、SEO 作業の負担を軽減する強力な武器です。記事の更新、外部リンクの公開、ランキング...

パートタイムの仕事を始める前に SEO を学ぶのにどれくらい時間がかかりますか?

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますパートタイ...

SEO ランキングに影響を与える 11 の要素

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますSEO ラ...