2小时快速搭建一个高可用的IM系统( 九 )

我们将文件存放到本地的一个磁盘文件夹下 , 然后发送给客户端路径 , 客户端通过路径加载相关的图片信息 。
关于发送图片 , 我们虽然实现功能 , 但是做的太简单了 , 我们在接下来的章节详细的和大家探讨一下系统优化相关的方案 。怎样让我们的系统在生产环境中用的更好 。
程序优化和系统架构升级方案
我们上边实现了一个功能健全的 IM 系统 , 要将该系统应用在企业的生产环境中 , 需要对代码和系统架构做优化 , 才能实现真正的高可用 。
本节主要从代码优化和架构升级上谈一些个人观点 , 能力有限不可能面面俱到 , 希望读者也在评论区给出更多好的建议 。
代码优化
我们的代码没有使用框架 , 函数和 API 都写的比较简陋 , 虽然进行了简单的结构化 , 但是很多逻辑并没有解耦 , 所以建议大家业界比较成熟的框架对代码进行重构 , Gin 就是一个不错的选择 。
系统程序中使用 clientMap 来存储客户端长链接信息 , Go 语言中对于大 Map 的读写要加锁 , 有一定的性能限制 。
在用户量特别大的情况下 , 读者可以对 clientMap 做拆分 , 根据用户 ID 做 Hash 或者采用其他的策略 , 也可以将这些长链接句柄存放到 redis 中 。
上边提到图片上传的过程 , 有很多可以优化的地方 , 首先是图片压缩(微信也是这样做的) , 图片资源的压缩不仅可以加快传输速度 , 还可以减少服务端存储的空间 。
另外对于图片资源来说 , 实际上服务端只需要存储一份数据就够了 , 读者可以在图片上传的时候做 Hash 校验 。
如果资源文件已经存在了 , 就不需要再次上传了 , 而是直接将 URL 返回给客户端(各大网盘厂商的妙传功能就是这样实现的) 。
代码还有很多优化的地方 , 比如我们可以将鉴权做的更好 , 使用 wss:// 代替 ws:// 。
在一些安全领域 , 可以对消息体进行加密 , 在高并发领域 , 可以对消息体进行压缩 。
对 MySQL 连接池再做优化 , 将消息持久化存储到 Mongo , 避免对数据库频繁的写入 , 将单条写入改为多条一块写入;为了使程序耗费更少的 CPU , 降低对消息体进行 Json 编码的次数 , 一次编码 , 多次使用......
系统架构升级
我们的系统太过于简单 , 所在在架构升级上 , 有太多的工作可以做 , 笔者在这里只提几点比较重要的:
①应用/资源服务分离
我们所说的资源指的是图片、视频等文件 , 可以选择成熟厂商的 Cos , 或者自己搭建文件服务器也是可以的 , 如果资源量比较大 , 用户比较广 , CDN 是不错的选择 。
②突破系统连接数 , 搭建分布式环境
对于服务器的选择 , 一般会选择 linux , Linux 下一切皆文件 , 长链接也是一样 。
单机的系统连接数是有限制的 , 一般来说能达到 10 万就很不错了 , 所以在用户量增长到一定程序 , 需要搭建分布式 。
分布式的搭建就要优化程序 , 因为长链接句柄分散到不同的机器 , 实现消息广播和分发是首先要解决的问题 , 笔者这里不深入阐述了 , 一来是没有足够的经验 , 二来是解决方案有太多的细节需要探讨 。
搭建分布式环境所面临的问题还有:怎样更好的弹性扩容、应对突发事件等 。
③业务功能分离
我们上边将用户注册、添加好友等功能和聊天功能放到了一起 , 真实的业务场景中可以将它们做分离 , 将用户注册、添加好友、创建群组放到一台服务器上 , 将聊天功能放到另外的服务器上 。
业务的分离不仅使功能逻辑更加清晰 , 还能更有效的利用服务器资源 。
④减少数据库I/O , 合理利用缓存
我们的系统没有将消息持久化 , 用户信息持久化到 MySQL 中去 。
在业务当中 , 如果要对消息做持久化储存 , 就要考虑数据库 I/O 的优化 , 简单讲:合并数据库的写次数、优化数据库的读操作、合理的利用缓存 。


推荐阅读