{"id":13461546,"url":"https://github.com/alberliu/gim","last_synced_at":"2025-05-15T03:02:52.766Z","repository":{"id":47219622,"uuid":"115840068","full_name":"alberliu/gim","owner":"alberliu","description":"golang写的IM服务器(服务组件形式)","archived":false,"fork":false,"pushed_at":"2025-05-05T11:03:43.000Z","size":978,"stargazers_count":2634,"open_issues_count":2,"forks_count":533,"subscribers_count":76,"default_branch":"main","last_synced_at":"2025-05-05T11:41:45.446Z","etag":null,"topics":["golang","im"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alberliu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-31T03:28:36.000Z","updated_at":"2025-05-05T10:35:37.000Z","dependencies_parsed_at":"2024-06-07T11:02:21.909Z","dependency_job_id":"40bf3ced-e65d-45fe-8e8b-4eb6a29e1267","html_url":"https://github.com/alberliu/gim","commit_stats":null,"previous_names":["alberliu/goim"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alberliu%2Fgim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alberliu%2Fgim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alberliu%2Fgim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alberliu%2Fgim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alberliu","download_url":"https://codeload.github.com/alberliu/gim/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254264737,"owners_count":22041789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","im"],"created_at":"2024-07-31T11:00:43.112Z","updated_at":"2025-05-15T03:02:52.744Z","avatar_url":"https://github.com/alberliu.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"### 简要介绍\ngim是一个即时通讯服务器，代码全部使用golang完成。主要特性  \n1.支持tcp，websocket接入  \n2.离线消息同步    \n3.单用户多设备同时在线    \n4.单聊，群聊，以及房间聊天场景  \n5.支持服务水平扩展  \n6.使用领域驱动设计  \n7.支持裸机部署和k8s部署  \ngim可以作为以业务服务器的一个组件，为现有业务服务器提供im的能力，业务服务器\n只需要实现user.int.proto协议中定义的GRPC接口，为gim服务提供基本的用户功能即可\n### 使用技术：\n数据库：MySQL+Redis  \n通讯框架：GRPC  \n长连接通讯协议：Protocol Buffers  \nORM框架：GORM\n### 安装部署\n1.首先安装MySQL，Redis  \n2.创建数据库gim，执行sql/create_table.sql，完成初始化表的创建（数据库包含提供测试的一些初始数据）  \n3.修改config下配置文件，使之和你本地配置一致，如果没有配置gim_env环境变量，默认会加载config/local_conf.go配置    \n4.分别切换到cmd的connect,logic,business目录下，执行go run main.go,启动TCP连接层服务器,WebSocket连接层服务器,逻辑层服务器,用户服务器  \n（注意：connect只能在linux下启动，如果想在其他平台下启动，请安装docker，执行cmd/connect/run.sh）  \n### 项目目录简介\n项目结构遵循 https://github.com/golang-standards/project-layout\n```\ncmd:          服务启动入口\nconfig:       服务配置\ndeploy        部署配置文件\ninternal:     服务私有代码\npkg:          服务共有代码\nsql:          项目sql文件\n```\n### 服务简介\n1.connect  \n维持与客户端的TCP和WebSocket长连接，心跳，以及TCP拆包粘包，消息编解码   \n2.logic  \n设备信息，好友信息，群组信息管理，消息转发逻辑  \n3.user  \n一个简单的用户服务，可以根据自己的业务需求，进行扩展,但是前提是，你的业务服务器实现了user.int.proto接口\n### 客户端接入流程\n1.调用RegisterDevice接口，完成设备注册，获取设备ID（device_id）,注意，一个设备只需完成一次注册即可，后续如果本地有device_id,就不需要注册了，举个例子，如果是APP第一次安装，就需要调用这个接口，后面即便是换账号登录，也不需要重新注册。  \n2.调用SignIn接口，完成账户登录，获取账户登录的token。  \n3.建立长连接，使用步骤2拿到的token，完成长连接登录。  \n如果是web端,需要调用建立WebSocket时,如果是APP端，就需要建立TCP长连接。  \n在完成建立TCP长连接时，第一个包应该是长连接登录包（SignInInput），如果信息无误，客户端就会成功建立长连接。  \n4.使用长连接发送消息同步包（SyncInput），完成离线消息同步，注意：seq字段是客户端接收到消息的最大同步序列号，如果用户是换设备登录或者第一次登录，seq应该传0。  \n接下来，用户可以使用LogicExt.SendMessage接口来发送消息，消息接收方可以使用长连接接收到对应的消息。\n### 单用户多设备支持，离线消息同步\n每个用户都会维护一个自增的序列号，当用户A给用户B发送消息是，首先会获取A的最大序列号，设置为这条消息的seq，持久化到用户A的消息列表，\n再通过长连接下发到用户A账号登录的所有设备，再获取用户B的最大序列号，设置为这条消息的seq，持久化到用户B的消息列表，再通过长连接下发\n到用户B账号登录的所有设备。  \n假如用户的某个设备不在线，在设备长连接登录时，用本地收到消息的最大序列号，到服务器做消息同步，这样就可以保证离线消息不丢失。\n### 读扩散和写扩散\n首先解释一下，什么是读扩散，什么是写扩散  \n#### 读扩散\n**简介**：群组成员发送消息时，先建立一个会话，都将这个消息写入这个会话中，同步离线消息时，需要同步这个会话的未同步消息  \n**优点**：每个消息只需要写入数据库一次就行，减少数据库访问次数，节省数据库空间  \n**缺点**：一个用户有n个群组，客户端每次同步消息时，要上传n个序列号，服务器要对这n个群组分别做消息同步  \n#### 写扩散\n**简介**：在群组中，每个用户维持一个自己的消息列表，当群组中有人发送消息时，给群组的每个用户的消息列表插入一条消息即可  \n**优点**：每个用户只需要维护一个序列号和消息列表  \n**缺点**：一个群组有多少人，就要插入多少条消息，当群组成员很多时，DB的压力会增大\n### 消息转发逻辑选型以及特点\n#### 群组：\n采用写扩散，群组成员信息持久化到数据库保存。支持消息离线同步。  \n#### 房间：  \n采用读扩散，会将消息短暂的保存到Redis，长连接登录消息同步不会同步离线消息。\n### 核心流程时序图\n#### 长连接登录\n![登录.png](https://upload-images.jianshu.io/upload_images/5760439-2e54d3c5dd0a44c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n#### 离线消息同步\n![离线消息同步.png](https://upload-images.jianshu.io/upload_images/5760439-aa513ea0de851e12.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n#### 心跳\n![心跳.png](https://upload-images.jianshu.io/upload_images/5760439-26d491374da3843b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n#### 消息单发\nc1.d1和c1.d2分别表示c1用户的两个设备d1和d2,c2.d3和c2.d4同理\n![消息单发.png](https://upload-images.jianshu.io/upload_images/5760439-35f1a91c8d7fffa6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n#### 群组消息群发\nc1,c2.c3表示一个群组中的三个用户\n![消息群发.png](https://upload-images.jianshu.io/upload_images/5760439-47a87c45b899b3f9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n### github\nhttps://github.com/alberliu/gim\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falberliu%2Fgim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falberliu%2Fgim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falberliu%2Fgim/lists"}