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

笔者 2019 年参加了一次 Gopher 大会 , 有幸听探探的架构师分享了他们 2019 年微服务化的过程 。

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

文章插图
图片来自 Pexels
本文快速搭建的 IM 系统也是使用 Go 语言来快速实现的 , 这里先和各位分享一下探探 App 的架构图:
2小时快速搭建一个高可用的IM系统

文章插图
 
本文的目的是帮助读者较为深入的理解 Socket 协议 , 并快速搭建一个高可用、可拓展的 IM 系统(文章标题纯属引人眼球 , 不是真的 , 请读者不要在意) , 同时帮助读者了解 IM 系统后续可以做哪些优化和改进 。
麻雀虽小 , 五脏俱全 , 该 IM 系统包含基本的注册、登录、添加好友基础功能 , 另外提供单聊、群聊 , 并且支持发送文字、表情和图片 , 在搭建的系统上 , 读者可轻松的拓展语音、视频聊天、发红包等业务 。
为了帮助读者更清楚的理解 IM 系统的原理:
  • 第一节深入讲解 WebSocket 协议 , WebSocket 是长链接中比较常用的协议 。
  • 第二节讲解快速搭建 IM 系统的技巧和主要代码实现 。
  • 第三节对 IM 系统的架构升级和优化提出一些建议和思路 。
  • 最后章节做本文的回顾总结 。
深入理解 WebSocket 协议
Web Sockets 的目标是在一个单独的持久连接上提供全双工、双向通信 。在 JAVAscript 创建了 WebSocket 之后 , 会有一个 HTTP 请求发送到浏览器以发起连接 。
在取得服务器响应后 , 建立的连接会将 HTTP 升级从 HTTP 协议交换为 WebSocket 协议 。
由于 WebSocket 使用自定义的协议 , 所以 URL 模式也略有不同 。未加密的连接不再是 http:// , 而是 ws://;加密的连接也不是 https:// , 而是 wss:// 。
在使用 WebSocket URL 时 , 必须带着这个模式 , 因为将来还有可能支持其他的模式 。
使用自定义协议而非 HTTP 协议的好处是 , 能够在客户端和服务器之间发送非常少量的数据 , 而不必担心 HTTP 那样字节级的开销 。由于传递的数据包很小 , 所以 WebSocket 非常适合移动应用 。
上文中只是对 Web Sockets 进行了笼统的描述 , 接下来的篇幅会对 Web Sockets 的细节实现进行深入的探索 。
本文接下来的几个小节不会涉及到大量的代码片段 , 但是会对相关的 API 和技术原理进行分析 , 相信大家读完下文之后再来看这段描述 , 会有一种豁然开朗的感觉 。
①WebSocket 复用了 HTTP 的握手通道
“握手通道”是 HTTP 协议中客户端和服务端通过"TCP 三次握手"建立的通信通道 。
客户端和服务端使用 HTTP 协议进行的每次交互都需要先建立这样一条“通道” , 然后通过这条通道进行通信 。
我们熟悉的 Ajax 交互就是在这样一个通道上完成数据传输的 , 只不过 Ajax 交互是短连接 , 在一次 Request→Response 之后 , “通道”连接就断开了 。
下面是 HTTP 协议中建立“握手通道”的过程示意图:
2小时快速搭建一个高可用的IM系统

文章插图
 
 
上文中我们提到:在 JavaScript 创建了 WebSocket 之后 , 会有一个 HTTP 请求发送到浏览器以发起连接 , 然后服务端响应 , 这就是“握手“的过程 。
在这个握手的过程当中 , 客户端和服务端主要做了两件事情:
建立了一条连接“握手通道”用于通信:这点和 HTTP 协议相同 , 不同的是 HTTP 协议完成数据交互后就释放了这条握手通道 , 这就是所谓的“短连接” , 它的生命周期是一次数据交互的时间 , 通常是毫秒级别的 。
将 HTTP 协议升级到 WebSocket 协议 , 并复用 HTTP 协议的握手通道 , 从而建立一条持久连接 。
说到这里可能有人会问:HTTP 协议为什么不复用自己的“握手通道” , 而非要在每次进行数据交互的时候都通过 TCP 三次握手重新建立“握手通道”呢?
答案是这样的:虽然“长连接”在客户端和服务端交互的过程中省去了每次都建立“握手通道”的麻烦步骤 。
但是维持这样一条“长连接”是需要消耗服务器资源的 , 而在大多数情况下 , 这种资源的消耗又是不必要的 , 可以说 HTTP 标准的制定经过了深思熟虑的考量 。


推荐阅读