# rabbit-im **Repository Path**: smallkingfisher/rabbit-im ## Basic Information - **Project Name**: rabbit-im - **Description**: rabbit-im是一款开源聊天软件 - **Primary Language**: Unknown - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-06-07 - **Last Updated**: 2024-01-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: Go语言 ## README ## 开源im: rabbit-im 写一款类似**qq**这样的通讯工具,是一件颇有成就感的事情。 与实验性的im不同,rabbit-im是一个一开始就使用微服务理念设计的即时通讯工具,有利于在云原生生产环境大规模部署。 至于如何商业化,我尚未去想过这些,我不认为在即时通讯领域后来者还能拿下微信和qq的市场,时机不同了。 写im是因为这种产品的后端框架是比较全面的,很容易转化成其它形式的产品。 张一鸣在做今日头条和抖音之前,做过yy语音直播和安居客这样的产品。 王兴在做成美团之前,做过校园网,人人网等产品。 程序员想要崛起,可能要做很多产品且未必有任何成功的机会,总归要有一些自己的代表作品。 $\color{#222514}{-}\color{#222514}{-}\color{#222514}{-}\color{#222514}{-}\color{#4285f4}{T}\color{#ea4335}{a}\color{#fbbc05}{n}\color{#4285f4}{g}\color{#34a853}{s}\color{#ea4335}{h}\color{#4285f4}{u}\color{#fbbc05}{n}\color{#34a853}{c}\color{#ea4335}{a}\color{#fbbc05}{i}$ **说明:** 从代码上面看,因为开发投入的人力有限,测试机器也有限,为了更快的开发出第一版本,目前实现的方式不是微服务,但留出了微服务的接口。版本说明: - v0.0.1 实现功能和可用性 - v0.0.2 优化系统架构 - v0.0.3 移动客户端适配 - v0.0.4 安全和加密 - v1.0.0-beta 优化数据编码、压缩,提升复杂网络下数据传输成功率 - v1.0.1-beta k8s 部署 - v1.1 Stable 提升数据库查询速度、减小消息延迟时间、事件不丢失、支撑2000万用户在线 ### IM架构 #### rabbit-im 拆分为4个子系统: - 信令系统 - IM业务系统 - 推送系统 - 存储系统 ```mermaid graph LR 系统拆分 --> 信令系统:用户注册/登录,用户信息查询,用户在线/离线统计; 系统拆分 --> IM业务系统:好友关系,群关系,消息推送,事件推送; 系统拆分 --> 推送系统:在线消息的推送,离线消息的推送; 系统拆分 --> 存储系统:mongodb集群,ceph集群分别负责消息和文件的存储和读取; ``` 信令系统: - 用户注册/登录/更新用户信息,维护用户在线状态 - 下行消息推送 IM业务: - 好友添加、好友列表、好友信息查看 - 创建群、邀请进群、解散群、剔除群成员、禁言、撤回群成员消息 - 聊天消息收发 - 离线消息拉取 - 系统(新闻/广告)推送 - 业务分发 推送系统: ```mermaid graph LR 推送系统 --> PushProxy代理用户的消息写入请求; 推送系统 --> Kafka消息队列; 推送系统 --> route路由到目标IM服务器; ``` 存储系统: - mongodb 集群 - ceph/minio/fastdfs存储集群 考虑性能问题,聊天消息按照冷热数据进行分离存储: 10天以内的数据,缓存在redis中 10~100天以内的数据存储在mysql中 100天以上的数据,按照时间戳分库分表(100天一个库) 图片存储缩略图、高清原图2种规格。客户端默认收到的是缩略图,点击后下载高清图 客户端定期(或缓存命中失败)从信令服务拉取好友在线状态,并缓存 **系统架构图:** ![](./icon/42e48248-e436-11ec-b6b9-8797422ac270.png) **部署方式:** k8s部署。 ### 长连接、短连接 rabbit-im最终的用户包含pc用户和移动客户端用户(安卓、ios),因此设计之初将网络连接考虑进去,设计原则如下: im的场景是集中性的(聊天的需求是突发,集中性的在某个时间段内聊天),因此在无聊天消息时只发送http短连接(3s间隔保活在线状态,服务端返回好友上下线状态),在有聊天消息时在2min之内长连接。 转发服务器用asmq(kafka/rabbit)实现,事件推送服务用websocket实现 ### 1 编译方法 ```shell git clone git@gitee.com:jacky6666/rabbit-im.git cd rabbit-im go mod tidy make all # 清理 make clean ``` ### 2 数据表 - 用户信息表 - 用户关系表 - 聊天消息表 **用户信息表 UserInfo** ```plantuml @startjson #highlight "uid" #highlight "Friends" #highlight "gids" #highlight "joingids" { "uid": 1, "username": "jack", "nickname": "画笔", "password": "123456", "facetype": 0, "customface": "pony", "customfacefmt": "fmt", "gender":0, "age":18, "height":175, "birthday":"2023-1-1", "signature":"生死看淡,不服就干", "address":"shen zhen", "telephonenumber":"13637110255", "mail":"001@qq.com", "registertime":"2023-1-1", "remark":"", "updatetime":"2023-1-1 12:00:00", "teaminfo":"同事", "Friends": [ { "fid":666, "markname":"阿红", "teamname":"升值加新群" }, { "fid":652, "markname":"阿燕", "teamname":"升值加新群" } ], "gids": [ 1239, 6411, 78956 ], "joingids":[ 123,9981,6556 ] } @endjson ``` **用户关系表 UserRelationship** ```plantuml @startjson { "uidsubmit":123, "uidgrantee":986, "fixed":true, "uidsmall":123, "uidbig":986, "user_smallteamname": "朋友", "user_smallmarkname": "如霞", "user_bigteamname": "学校", "user_bigmarkname": "班主任", "updatetime":"2023-1-1", "remark":"备注" } @endjson ``` **聊天消息表 ChatMessages** ```plantuml @startjson { "senderuid":123, "reseiveduid":961, "msgcontent": "晚上去吃火锅吗?", "createtime":"2023-12-31", "remark":"" } @endjson ``` #### 为mongodb数据库创建超级管理员用户 ```shell > use admin switched to db admin > db.createUser( ... { ... user: "adminUser", ... pwd: "admin123", ... roles: [{role: "userAdminAnyDatabase",db:"admin"}] ... } ... ) Successfully added user: { "user" : "adminUser", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } > ``` #### 为某个数据库单独创建普通用户 *user rabbit数据库,如果存在则切换到该数据库,如果不存在则创建* *为rabbit数据库创建用户,账号为user123,密码为123456* ```shell > use rabbit > db.createUser({user:"user123",pwd:"123456",roles:[{role:"readWrite",db:"rabbit"},{role:"dbAdmin",db:"rabbit"},{role:"userAdmin",db:"rabbit"}]}) ``` #### 测试mongodb数据库写入 ![](./icon/a4dbf40a-e363-11ec-92bb-83c62e614ffb.png) ### 3 回包格式 **说明:** - 信息(控制)流:用户注册、用户登录、加好友、加群、退群、解散群、剔除群成员、禁言、撤回群成员消息、设置头像、设置邮箱、获取好友列表 - 消息(数据)流:专指聊天消息(文字、表情、语音、视频、图片、文件、链接分享) **回包统一格式:** ```json { "restapi" : "", "cmdbody" : {}, "msgbody": {} } ``` | 字段 | 类型 | 说明 | | ---- | ---- | ---- | | restapi | String | 客户端所请求的rest api,例如"register"、"login"、"userlist"、"grouplist" | | cmdbody | Object | 信息元素的内容,不同的 restapi 有不同的 cmdbody 格式,具体参见下文。 | #### 信息流 CmdBody 说明: > cmdbody 中填写的字段是命令内容。rabbit IM 支持一条消息中包括多种消息元素类别。 #### 消息流 MsgBody 说明: > msgbody 中所填写字段是消息内容。rabbit IM 支持一条消息中包括多种消息元素类别,例如一条消息中既包括文本消息元素,还包括表情消息元素。因此 MsgBody 定义为 Array 格式,可按照需求加入多类消息元素。消息元素名称为 RIMMsgElement,消息元素 RIMMsgElement 组成 MsgBody 的示例请参见 消息内容 MsgBody 实例。 消息元素 RBTMsgElement 的格式统一为: ```json { "msgtype": "", "message": {} } ``` | 字段 | 类型 | 说明 | | ---- | ---- | ---- | | msgtype | String | 消息元素类别;目前支持的消息对象包括:RIMTextElem(文本消息)、RIMLocationElem(位置消息)、RIMFaceElem(表情消息)、RIMCustomElem(自定义消息)、RIMSoundElem(语音消息)、RIMImageElem(图像消息)、RIMFileElem(文件消息)、RIMVideoFileElem(视频消息) | | message | Object | 消息元素的内容,不同的 msgtype 有不同的 message 格式,具体参见下文。 | 目前支持消息类别 MsgType 见下表: | msgtype的值 | 类型 | | ---- | ---- | | RIMTextElem | 文本消息 | | RIMLocationElem | 地理位置消息 | | RIMFaceElem | 表情消息 | | RIMCustomElem | 自定义消息,当接收方为 iOS 系统且应用处在后台时,此消息类型可携带除文本以外的字段到 APNs。一条组合消息中只能包含一个 RIMCustomElem 自定义消息元素。 | | RIMSoundElem | 语音消息 | | RIMImageElem | 图像消息 | | RIMFileElem | 文件消息 | | RIMVideoFileElem | 视频消息 | ### 4 api测试 **1 注册新用户:** 请求: ```shell curl -X POST http://127.0.0.1:8082/register -d '{"username":"jack1234","password":"123456"}' --header "Content-Type: application/json" ``` 返回: ```json { "restapi":"register", "cmdbody":{ "uid":10079, "username":"jack1234", "password":"123456", "facetype":0, "customface":"", "customfacefmt":0, "gender":0, "birthday":"2000-02-04T10:30:00+08:00", "Remark":"", "updatetime":"2022-06-13T00:23:40.320148698+08:00" } } ``` **2 用户登录** 请求: ```shell curl -X POST http://127.0.0.1:8082/login/jack/123456 ``` 返回: ```json { "restapi":"login", "cmdbody":{ "statuscode":0, "errmsg":"", "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTUwNTQzMDIsImlhdCI6MTY1NTA1MDcwMiwibmFtZSI6ImdnIn0.iuKHepSPM_5HhALcY8-TZckbdOKYda1E-KQzCLZuy94" } } ```