キーボードが乾燥しているピックアップ:私の素手と一緒に配布さIMシステムを開発します

1はじめに

定期的な読者は、私はナショナルデー前の最後の年でシェアを持っていた思い出すかもしれ「技術的なドライ品:最初から、あなたに百万のメッセージプッシュシステムを教えるために設計された」、私はテキストで擬似コードの一部を掲載しているものの、何人かの友人はまだ願っていますあなたは直接ソースコードの一部を実行することができます共有することができます。まあ、私は私が悪い何も言うことはありません疑う(それは本当に悪いので...)、私は大きな戦いをプルアップするために、このキーボードは準備ができて絶対に不可能である容量ラインとコードを疑うので、 - IM分散フリーハンドのラインとのセットアウト!^ _ ^!

-この記事では、私が開発した学習者のために設計されたIM IMシステム文書CIMの開発者は、IMの水平展開することができ、独自の構築を支援するためにいくつかのコンポーネントを提供しながら、:(CROSS-IMフルネームを)。

この記事とCIMコードの研究を通して、あなたは、以下の情報を取得することができます。

1)どのように私は私を許して許して、少し弱い(ゼロからCIMの顧客をIMを開発します)。

2)IMの分散アーキテクチャを設計する方法。

3)どのようにあなたのIMは、コ​​ードや関連技術でそれらを達成するためのアーキテクチャを分散します。

CIMの送信元アドレスをサポートするこの記事:

メイン画像:https://github.com/crossoverJie/cim

代替ミラー:https://github.com/52im/cim

*ヒント:この記事とCIMのソースを読んで、あなたはこれらを持っていない場合は、お読みください、などのネットワークプログラミング、IM理論、いくつかの知識を持っているあなたを必要とし、「1はじめに十分である:ゼロからモバイルエンドIMを開発します」、そして、完全に!

同期に発表されたこの記事:http://www.52im.net/thread-2775-1-1.html

著者について2、 

crossoverJie(陳潔):90は、今重慶豚ネットワーク限定で、情報工学の重慶大学を卒業しました。

3、デモを実行

2つの特別に記録されたビデオプレゼンテーション(グループチャット、プライベートチャット)、あなたはビデオ版のデモを表示するには、以下のリンクをクリックすることができます。

CIMのささやきビデオ・プレゼンテーション:https://www.bilibili.com/video/av39405821

CIMグループチャットビデオプレゼンテーション:https://www.bilibili.com/video/av39405501

4、アーキテクチャ設計

のは、特定のアーキテクチャを見てみましょう:

 

アーキテクチャの説明:

1)CIM様々な構成要素はSpringBootを構築する際に使用されます。

2)建設ネッティー+ Googleのプロトコルバッファの下の通信。

3)Redisのは、各クライアントのアカウント情報、オンライン状態のルーティング情報を格納します。

4)IM-サーバーサービスと発見のための飼育係に署名します。

全体的には、以下のモジュールで構成されています。

1)CIMサーバ - IMサーバ:クライアント接続を受信するための手段は、透過的にメッセージ、メッセージのプッシュ機能を送信します。クラスタの展開をサポートしています。

2)CIMフォワードroute--メッセージルーティングサーバー:メッセージルーティング、メッセージ転送、ユーザーのログイン、ユーザーのオフラインといくつかの運用ツール(利用可能なオンラインユーザなど)を処理するための手段と、

3)CIMクライアント - IMクライアント:エンド・ユーザーへのメッセージを、そしてコミュニケーションその他(グループチャット、プライベートチャット)を起動するコマンドを開始し、かつ使いやすい一般的なコマンドの一部を構築しました。

図5に示すように、論理流れ図

全体のプロセスは、以下のフローチャートは比較的簡単です:

 

プロセスは次のように説明されます。

1)クライアントルートを開始にログインします。

2)クライアントに利用可能に成功したログインIM-サーバーを選択し、保存するには、ルートのRedisから飼育係に情報を記録し、

3)IM-サーバーにクライアントが成功した後に、ハートビートを保持し、接続長を開始します。

4)端末状態情報オフラインを介してクライアントルートを削除。

これは、次の手順を必要とするとき、私たち自身の展開:

1)ミドルウェア基盤を設定  のRedis飼育係は

2)展開CIM-サーバー、これはサポートのレベルができるだけで同じ飼育係に登録する必要が拡張させ、性能要件を満たすために、実際のIMサーバです。

3)部署 cim-forward-route,这是路由服务器,所有的消息都需要经过它。由于它是无状态的,所以也可以利用 Nginx 代理提高可用性;

4)cim-client 真正面向用户的客户端;启动之后会自动连接 IM 服务器便可以在控制台收发消息了。

更多使用介绍可以参考快速启动

接下来各章将重点看看具体的详细设计实现,比如群聊、私聊消息如何流转;IM 服务端负载均衡;服务如何注册发现等等。

6、IM 服务端

先来看看服务端:主要是实现客户端上下线、消息下发等功能。

首先是服务启动:

 
 

由于是在 SpringBoot 中搭建的,所以在应用启动时需要启动 Netty 服务。

从 pipline 中可以看出使用了 Protobuf 的编解码(具体报文在客户端中分析,相关知识请见:《Protobuf通信协议详解:代码演示、详细原理介绍等》)。

7、注册发现

需要满足 IM 服务端的水平扩展需求,所以 cim-server 是需要将自身数据发布到注册中心的。这里参考之前分享的《搞定服务注册与发现》有具体介绍。

所以在应用启动成功后需要将自身数据注册到 Zookeeper 中:

 
 

最主要的目的就是将当前应用的 ip + cim-server-port+ http-port 注册上去:

 

上图是我在演示环境中注册的两个 cim-server 实例(由于在一台服务器,所以只是端口不同)。这样在客户端(监听这个 Zookeeper 节点)就能实时的知道目前可用的服务信息。

8、登录

当客户端请求 cim-forward-route 中的登录接口(详见下文)做完业务验证(就相当于日常登录其他网站一样)之后,客户端会向服务端发起一个长连接。

如之前的流程所示:

 

这时客户端会发送一个特殊报文,表明当前是登录信息。服务端收到后就需要将该客户端的 userID 和当前 Channel 通道关系保存起来。

 
 

同时也缓存了用户的信息,也就是 userID 和 用户名。

9、离线消息

当客户端断线后也需要将刚才缓存的信息清除掉。

 

同时也需要调用 route 接口清除相关信息(具体接口看下文)。

10、IM 路由

 

从架构图中可以看出,路由层是非常重要的一环;它提供了一系列的 HTTP 服务承接了客户端和服务端。

目前主要是以下几个接口。

10.1 注册接口

 
 

由于每一个客户端都是需要登录才能使用的,所以第一步自然是注册。

这里就设计的比较简单,直接利用 Redis 来存储用户信息;用户信息也只有 ID 和 userName 而已。只是为了方便查询在 Redis 中的 KV 又反过来存储了一份 VK,这样 ID 和 userName 都必须唯一。

10.2 登录接口

这里的登录和 cim-server 中的登录不一样,具有业务性质:

 

具体的流程:

1)登录成功之后需要判断是否是重复登录(一个用户只能运行一个客户端);

2)登录成功后需要从 Zookeeper 中获取服务列表(cim-server)并根据某种算法选择一台服务返回给客户端;

3)登录成功之后还需要保存路由信息,也就是当前用户分配的服务实例保存到 Redis 中。

为了实现只能一个用户登录,使用了 Redis 中的 set 来保存登录信息;利用 userID 作为 key ,重复的登录就会写入失败。

 

 

 

类似于 Java 中的 HashSet,只能去重保存。

获取一台可用的路由实例也比较简单:

 

1)先从 Zookeeper 获取所有的服务实例做一个内部缓存;

2)轮询选择一台服务器(目前只有这一种算法,后续会新增)。

当然要获取 Zookeeper 中的服务实例前自然是需要监听 cim-server 之前注册上去的那个节点。

具体代码如下:

 
 
 

也是在应用启动之后监听 Zookeeper 中的路由节点,一旦发生变化就会更新内部缓存。这里使用的是 Guava 的 cache,它基于 ConcurrentHashMap,所以可以保证清除、新增缓存的原子性。

10.3 群聊接口

这是一个真正发消息的接口,实现的效果就是其中一个客户端发消息,其余所有客户端都能收到!流程肯定是客户端发送一条消息到服务端,服务端收到后在上文介绍的 SessionSocketHolder 中遍历所有 Channel(通道)然后下发消息即可。服务端是单机倒也可以,但现在是集群设计。所以所有的客户端会根据之前的轮询算法分配到不同的 cim-server 实例中。

因此就需要路由层来发挥作用了。

 
 

路由接口收到消息后首先遍历出所有的客户端和服务实例的关系。

路由关系在 Redis 中的存放如下:

 

由于 Redis 单线程的特质,当数据量大时;一旦使用 keys 匹配所有 cim-route:* 数据,会导致 Redis 不能处理其他请求。所以这里改为使用 scan 命令来遍历所有的 cim-route:*。

接着会挨个调用每个客户端所在的服务端的 HTTP 接口用于推送消息。

在 cim-server 中的实现如下:

 
 

cim-server 收到消息后会在内部缓存中查询该 userID 的通道,接着只需要发消息即可。

10.4 在线用户接口

这是一个辅助接口,可以查询出当前在线用户信息。

 
 

实现也很简单,也就是查询之前保存 ”用户登录状态的那个去重 set “即可。

10.5 私聊接口

之所以说获取在线用户是一个辅助接口,其实就是用于辅助私聊使用的。一般我们使用私聊的前提肯定得知道当前哪些用户在线,接着你才会知道你要和谁进行私聊。

类似于这样:

 

在我们这个场景中,私聊的前提就是需要获得在线用户的 userID:

 

所以私聊接口在收到消息后需要查询到接收者所在的 cim-server 实例信息,后续的步骤就和群聊一致了。调用接收者所在实例的 HTTP 接口下发信息。只是群聊是遍历所有的在线用户,私聊只发送一个的区别。

10.6 下线接口

一旦客户端下线,我们就需要将之前存放在 Redis 中的一些信息删除掉(路由信息、登录状态)。

 
 

11、IM 客户端

客户端中的一些逻辑其实在上文已经谈到一些了。

11.1 登录

第一步也就是登录,需要在启动时调用 route 的登录接口,获得 cim-server 信息再创建连接。

 
 
 

登录过程中 route 接口会判断是否为重复登录,重复登录则会直接退出程序。

 

接下来是利用 route 接口返回的 cim-server 实例信息(ip+port)创建连接。最后一步就是发送一个登录标志的信息到服务端,让它保持客户端和 Channel 的关系。

 

11.2 自定义协议

上文提到的一些登录报文、真正的消息报文这些其实都是在我们自定义协议中可以区别出来的。由于是使用 Google Protocol Buffer 编解码,所以先看看原始格式。

 

其实这个协议中目前一共就三个字段:

1)requestId 可以理解为 userId;

2)reqMsg 就是真正的消息;

3)type 也就是上文提到的消息类别。

目前主要是三种类型,分别对应不同的业务:

 

11.3 心跳

为了保持客户端和服务端的连接,每隔一段时间没有发送消息都需要自动的发送心跳。

目前的策略是每隔一分钟就是发送一个心跳包到服务端:

 
 

这样服务端每隔一分钟没有收到业务消息时就会收到 ping 的心跳包:

 

11.4 内置命令

客户端也内置了一些基本命令来方便使用。

 
 

比如输入 :q 就会退出客户端,同时会关闭一些系统资源。

 
 

当输入 :olu(onlineUser 的简写)就会去调用 route 的获取所有在线用户接口。

 
 

11.5 群聊

群聊的使用非常简单,只需要在控制台输入消息回车即可。这时会去调用 route 的群聊接口。

 

11.6 私聊

私聊也是同理,但前提是需要触发关键字;使用 userId;;消息内容 这样的格式才会给某个用户发送消息,所以一般都需要先使用 

lu 命令获取所以在线用户才方便使用。

 

11.7 消息回调

为了满足一些定制需求,比如消息需要保存之类的。所以在客户端收到消息之后会回调一个接口,在这个接口中可以自定义实现。

 
 

因此先创建了一个 caller 的 bean,这个 bean 中包含了一个 CustomMsgHandleListener 接口,需要自行处理只需要实现此接口即可。

11.8 自定义界面

由于我自己不怎么会写界面,但保不准有其他大牛会写。所以客户端中的群聊、私聊、获取在线用户、消息回调等业务(以及之后的业务)都是以接口形式提供。

也方便后面做页面集成,只需要调这些接口就行了;具体实现不用怎么关心。

12、本文小结

cim 目前只是第一版,BUG 多,功能少(只拉了几个群友做了测试);不过后续还会接着完善,至少这一版会给那些没有相关经验的朋友带来一些思路。

后续计划:

 

本文同步发布于:http://www.52im.net/thread-2775-1-1.html

おすすめ

転載: www.cnblogs.com/imteck4713/p/11672402.html