分享利用 redis 订阅与发布特性,巧妙的现实高性能im系统。为表诚意,先贴源码地址:https://github.com/2881099/im
下载源码后的运行方法:
运行环境:.NETCore 2.1 + redis-server 2.8
下载Redis-x64-2.8.2402.zip,点击 start.bat 运行;或者修改 imServer、web 下面 appsettings.json redis 配置,指向可用的redis-server
cd imServer && dotnet run --urls="http://0.0.0.0:6001"
cd web && dotnet run --urls="http://0.0.0.0:5555"
打开多个浏览器,访问 http://127.0.0.1:5555 发送群消息
设计思路
socket选型
最二的办法是浏览器端使用websocket,其他端socket,这么混乱的设计最终将非常难维护。
所以强烈建议所有端都使用websocket协议,adorid/ios/h5/小程序全部支持websocket客户端。
业务与通讯协议
im系统一般涉及【我的好友】、【我的群】、【历史消息】等等。。
那么,imServer与业务方(web)该保持何种关系呢?
用户A向好友B发送消息,分析一下:
- 需要判断B是否为A好友;
- 需要判断A是否有权限;
- 等等。。
诸如此类业务判断会很复杂,我们试想一下,如果使用imServer做业务协议,它是不是会变成巨无霸难以维护。
又假如获取历史记录,难道客户端要先websocket.send('gethistory'),再在onmessage里定位回调处理?
这样做十分之二。。。
咱这样设计,所有用户的主动行为走业务方(web),imServer只负责即时消息推送。什么意思?
用户A向好友B发送消息:客户端请求业务方(web)接口,由业务方(web)后端向imServer发起推送请求,imServer收到指令后,向前端用户B的websocket发送数据,用户B收到了消息。
获取历史消息:客户端请求业务方(web)接口,返回json(历史消息)
回执:用户A如何知道消息发送状态(成功或失败或不在线)?imServer端向用户B发送消息时,把状态以消息的方式推给用户A即可(按上面的逻辑),具体请看源码吧。。。
web通知imServer性能优化
采用消息队列,redis的发布订阅最为轻量。
实现多节点部署
单个imServer实例支持多少websocket连接,几百个没问题吧,好。。。
如果系统在线用户有1万人,怎么办???
可以根据id的hash分区,比如部署4个imServer:
- imServer1 订阅 redisChanne1
- imServer2 订阅 redisChanne2
- imServer3 订阅 redisChanne3
- imServer4 订阅 redisChanne4
业务方(web)端根据接收方的id的hash分区算法,定位到对应的redisChannel,这样publish就可以将消息定位到相应的imServer了