网络编程

网络通信协议

OSI 七层模型

互联网的核心是一系列协议,总称为”互联网协议”(Internet Protocol Suite),正是这一些协议规定了电脑如何连接和组网。
主要协议分为:
Socket
- 接口抽象层
TCP / UDP
- 面向连接(可靠) / 无连接(不可靠)
HTTP1.1 / HTTP2 / QUIC(HTTP3)
- 超文本传输协议

socket 抽象层

应用程序通常通过“套接字”向网络发出请求或者应答网络请求。

一种通用的面向流的网络接口

主要操作:

  • 建立、接受连接
  • 读写、关闭、超时
  • 获取地址、端口

TCP 可靠连接,面向连接的协议

TCP/IP 即传输控制协议/网间协议,是一种面向连接(连接导向)的、可靠的、基于字节流的传输层(Transport layer)通信协议,因为是面向连接的协议。

服务端流程:

  • 监听端口
  • 接收客户端请求建立连接
  • 创建 goroutine 处理连接

客户端流程:

  • 建立与服务端的连接
  • 进行数据收发
  • 关闭连接

UDP 不可靠连接,允许广播或多播

UDP 协议(User Datagram Protocol)中文名称是用户数据报协议,是 OSI(Open System Interconnection,开放式系统互联)参考模型中一种无连接的传输层协议。

一个简单的传输层协议:

  • 不需要建立连接
  • 不可靠的、没有时序的通信
  • 数据报是有长度(65535-20=65515)
  • 支持多播和广播
  • 低延迟,实时性比较好
  • 应用于用于视频直播、游戏同步

http 超文本传输协议

HTTP(HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,它详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

请求报文:

  • Method: HEAD/GET/POST/PUT/DELETE
  • Accept:text/html、application/json
  • Content-Type:
    • application/json
    • application/x-www-form-urlencoded
  • 请求正文

响应报文:

  • 状态行(200/400/500)
  • 响应头(Response Header)
  • 响应正文

gRPC 基于 HTTP2 协议扩展

  • Request:
  • Headers
    :method = POST
    :scheme = https
    :path = /api.echo.v1.Echo/SayHello
    content-type = application/grpc+proto
    grpc-encoding = gzip
  • Data
  • Data:
    1 byte of zero (not compressed).
    network order 4 bytes of proto message length.
    serialized proto message.

HTTP2 如何提升网络速度

http1.x

  • keep_alive
  • 多域名

http2

  • 分桢,二进制协议,不再是超文本传输
  • 多路复用
  • 服务端推送

http2

  • 分桢,二进制协议,不再是超文本传输
  • 多路复用
  • 服务端推送

HTTP/1.1 为网络效率做了几点优化:

  • 增加了持久连接,每个请求进行串行请求。
  • 浏览器为每个域名最多同时维护 6 个 TCP 持久连接。
  • 使用 CDN 的实现域名分片机制。
    HTTP/2 的多路复用:
  • 请求数据二进制分帧层处理之后,会转换成请求 ID 编号的帧,通过协议栈将这些帧发送给服务器。
  • 服务器接收到所有帧之后,会将所有相同 ID 的帧合并为一条完整的请求信息。
  • 然后服务器处理该条请求,并将处理的响应行、响应头和响应体分别发送至二进制分帧层。
  • 同样,二进制分帧层会将这些响应数据转换为一个个带有请求 ID 编号的帧,经过协议栈发送给浏览器。
  • 浏览器接收到响应帧之后,会根据 ID 编号将帧的数据提交给对应的请求。

所以,HTTP2 通过引入二进制分帧层,就实现了 HTTP 的多路复用

HTTP 超文本传输协议-演进

HTTP 发展史:

  • 1991 年发布初代 HTTP/0.9 版
  • 1996 年发布 HTTP/1.0 版
  • 1997 年是 HTTP/1.1 版,是到今天为止传输最广泛的版本
  • 2015 年发布了 HTTP/2.0 版,优化了 HTTP/1.1 的性能和安全性
  • 2018 年发布的 HTTP/3.0 版,使用 UDP 取代 TCP 协议
    HTTP2:
  • 二进制分帧,按帧方式传输
  • 多路复用,代替原来的序列和阻塞机制
  • 头部压缩,通过 HPACK 压缩格式
  • 服务器推送,服务端可以主动推送资源
    HTTP3:
  • 连接建立延时低,一次往返可建立 HTTPS 连接
  • 改进的拥塞控制,高效的重传确认机制
  • 切换网络保持连接,从 4G 切换到 WIFI 不用重建连接

HTTPS 超文本传输安全协议

HTTPS;常称为 HTTP over TLS、HTTP over SSL 或 HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。
SSL 1.0、2.0 和 3.0:

  • SSL(Secure Sockets Layer)是网景公司(Netscape)设计的主要用于 Web 的安全传输协议,这种协议在 Web 上获得了广泛的应用。
    TLS 1.0:
  • IETF 将 SSL 标准化,即 RFC 2246 ,并将其称为 TLS(Transport Layer Security)。
    TLS 1.1:
  • 添加对 CBC 攻击的保护、支持 IANA 登记的参数。
    TLS 1.2:
  • 增加 SHA-2 密码散列函数、增加 AEAD 加密算法,如 GCM 模式、添加 TLS 扩展定义和 AES 密码组合。
    TLS 1.3:
  • 较 TLS 1.2 速度更快,性能更好、更加安全。

SSL/ TLS 重要概念

SSL/TLS 协议提供主要的作用有:

  • 认证用户和服务器,确保数据发送到正确的客户端和服务器。
  • 加密数据以防止数据中途被窃取。
  • 维护数据的完整性,确保数据在传输过程中不被改变。
    哈希算法:
  • CA 用自己的私钥对指纹签名,浏览器通过内置 CA 跟证书公钥进行解密,如果解密成功就确定证书是 CA 颁发的。
    对称加密:
  • 指的就是加、解密使用的同是一串密钥,所以被称做对称加密。对称加密只有一个密钥作为私钥。
    非对称加密:
  • 指的是加、解密使用不同的密钥,一把作为公开的公钥,另一把作为私钥。公钥加密的信息,只有私钥才能解密。
    CA 证书机构:
  • CA 是负责签发证书、认证证书、管理已颁发证书的机关;
  • 通常内置在操作系统,或者浏览器中,防止。

TLS 1.2 如何解决安全问题?

要解决的问题:

  • 防窃听(eavesdropping),对应加密(Confidentiality)
  • 防篡改(tampering),对应完整性校验(Integrity)
  • 防伪造(forgery),对应认证过程(Authentication)
    如何保证公钥不被篡改?
  • 解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。
    公钥加密计算量太大,如何减少耗用的时间?
  • 解决方法:每一次对话(session),客户端和服务器端都生成一个“对话密钥”(session key),用它来加密信息。由于“对话密钥”是对称加密,所以运算速度非常快,而服务器公钥只用于加密“对话密钥”本身,这样就减少了加密运算的消耗时间。
    因此,SSL/TLS 协议的基本过程:
  • 客户端向服务器端索要证书,并通过签名验证公钥。
  • 双方协商生成“对话密钥”,加密类型、随机串(非对称加密)。
  • 双方采用“对话密钥”进行加密通信(对称加密)。

TLS 1.3 Faster & More Secure

TLS 1.3 与之前的协议有较大差异,主要在于:

  • RSA 密钥交换被废弃,引入新的密钥协商机制 PSK。
  • 支持 0-RTT 数据传输,复用 PSK 无握手时间。
  • 废弃若干加密组件,SHA1、MD5 等 hash 算法。
  • 不再允许压缩加密报文,不允许重协商,不发 Change Cipher 了。

密钥协商机制:

  • RSA 是常用且简单的一个交换密钥的算法,即客户端决定密钥后,用服务器的公钥加密传输给对方,这样通信双方就都有了后续通信的密钥。
  • Diffie–Hellman(DH)是另一种交换密钥的算法,客户端和服务器都生成一对公私钥,然后将公钥发送给对方,双方得到对方的公钥后,用数字签名确保公钥没有被篡改,然后与自己的私钥结合,就可以计算得出相同的密钥。

为了保证前向安全,TLS 1.3 中 移除了 RSA 算法,Diffie–Hellman 是 唯一 的密钥交换算法。

Go 实现网络编程基础

基础概念:

  • Socket:数据传输
  • Encoding:内容编码
  • Session:连接会话状态
  • C/S 模式:通过客户端实现双端通信
  • B/S 模式:通过浏览器即可完成数据的传输

简单例子

  • 通过 TCP/UDP 实现网络通信

网络轮询器

  • 多路复用模型
  • 多路复用模块
  • 文件描述符
  • Goroutine 唤醒

Go 网络编程 - I/O 模型

I/O 模型

  • 阻塞 I/O
  • 非阻塞 I/O
  • 异步 I/O

I/O 多路复用

  • linux 下 select 函数或者 Epoll 库
  • windows 完成端口

Linux 下主要的 IO 模型分为:

  • Blocking IO - 阻塞 I O
  • Nonblocking IO - 非阻塞 IO
  • IO multiplexing - IO 多路复用
  • Signal-driven IO - 信号驱动式 IO(异步阻塞)
  • Asynchronous IO - 异步 IO

同步:调用端会一直等待服务端响应,直到返回结果。
阻塞:服务端返回结果之前,客户端线程会被挂起,此时线程不可被 CPU 调度,线程暂停运行。
非阻塞:在服务端返回前,函数不会阻塞调用端线程,而会立刻返回。
异步:调用端发起调用之后不会立刻返回,不会等待服务端响应,直到产生一个信号或执行一个基于线程的回调函数来完成这次 I/O 处理过程。

Go 网络编程 - I/O 多路复用

Go 语言在采用 I/O 多路复用 模型处理 I/O 操作,但是他没有选择最常见的系统调用 select,例如在 Linux 上使用 Epoll。虽然 select 也可以提供 I/O 多路复用的能力,但是使用它有比较多的限制:

  • 监听能力有限 — 最多只能监听 1024 个文件描述符;
  • 内存拷贝开销大 — 需要维护一个较大的数据结构存储文件描述符,该结构需要拷贝到内核中;
  • 时间复杂度 𝑂(𝑛) — 返回准备就绪的事件个数后,需要遍历所有的文件描述符;

I/O 多路复用:进程阻塞于 select,等待多个 IO 中的任一个变为可读,select 调用返回,通知相应 IO 可以读。 它可以支持单线程响应多个请求这种模式。

Go 网络编程 - 多路复用模块

为了提高 I/O 多路复用的性能
不同的操作系统也都实现了自己的 I/O 多路复用函数,例如:epoll、kqueue 和 evport 等
Go 语言为了提高在不同操作系统上的 I/O 操作性能,使用平台特定的函数实现了多个版本的网络轮询模块:
src/runtime/netpoll_epoll.go
src/runtime/netpoll_kqueue.go
src/runtime/netpoll_solaris.go
src/runtime/netpoll_windows.go
src/runtime/netpoll_aix.go
src/runtime/netpoll_fake.go

Goim 长连接网关

Goim 长连接 TCP 编程 - 概览

  • 项目地址: https://github.com/Terry-Mao/goim
  • Comet
    长连接层,主要是监控外网 TCP/Websocket 端口,并且通过设备 ID 进行绑定 Channel 实现,以及实现了 Room 合适直播等大房间消息广播。
  • Logic
    逻辑层,监控连接 Connect、Disconnect 事件,可自定义鉴权,进行记录 Session 信息(设备 ID、ServerID、用户 ID),业务可通过设备 ID、用户 ID、RoomID、全局广播进行消息推送。
  • Job
    通过消息队列的进行推送消峰处理,并把消息推送到对应 Comet 节点。

各个模块之间通过 gRPC 进行通信

Goim 长连接 TCP 编程 - 协议设计

  • 自定义协议设计
    4bytes 包长度(大小端)
    2bytes 头长度
    2bytes 协议版本
    4bytes 操作码 Auth 鉴权,心跳,业务等
    4bytes 请求序号 ID Sequence
    不限长度 Body

主要以包/针方式:

  • Package Length,包长度
    Header Length,头长度
  • Protocol Version,协议版本
  • Operation,操作码
  • Sequence 请求序号 ID
  • Body,包内容

Operation:

  • Auth
  • Heartbeat
  • Message

Sequence

  • 按请求、响应对应递增 ID

Goim 长连接 TCP 编程 - 边缘节点

Comet 长连接连续节点,通常部署在距离用户比较近,通过 TCP 或者 Websocket 建立连接,并且通过应用层 Heartbeat 进行保活检测,保证连接可用性。
节点之间通过云 VPC 专线通信,按地区部署分布。
国内:

  • 华北(北京)
  • 华中(上海、杭州)
  • 华南(广州、深圳)
  • 华西(四川)
    国外:
  • 日本、美国、欧洲

Goim 长连接 TCP 编程 - 负载均衡

长连接负载均衡比较特殊,需要按一定的负载算法进行分配节点,可以通过 HTTPDNS 方式,请求获致到对应的节点 IP 列表,例如,返回固定数量 IP,按一定的权重或者最少连接数进行排序,客户端通过 IP 逐个重试连接;

  • Comet 注册 IP 地址,以及节点权重,定时 Renew 当前节点连接数量;
  • Balancer 按地区经纬度计算,按最近地区(经纬度)提供 Comet 节点 IP 列表,以及权重计算排序;
  • BFF 返回对应的长连接节点 IP,客户端可以通过 IP 直接连;
  • 客户端 按返回 IP 列表顺序,逐个连接尝试建立长连接

Goim 长连接 TCP 编程 - 心跳保活机制

长连接断开的原因:

  • 长连接所在进程被杀死
  • NAT 超时
  • 网络状态发生变化,如移动网络 & Wifi 切换、断开、重连
  • 其他不可抗因素(网络状态差、DHCP 的租期等等 )

高效维持长连接方案

  • 进程保活(防止进程被杀死)
  • 心跳保活(阻止 NAT 超时)
  • 断线重连(断网以后重新连接网络)

自适应心跳时间

  • 心跳可选区间,[min=60s,max=300s]
  • 心跳增加步长,step=30s
  • 心跳周期探测,success=current + step、fail=current - step

Goim 长连接 TCP 编程 - 用户鉴权和 Session 信息

用户鉴权,在长连接建立成功后,需要先进行连接鉴权,并且绑定对应的会话信息;
Connect,建立连接进行鉴权,保存 Session 信息:

  • DeviceID,设备唯一 ID
  • Token,用户鉴权 Token,认证得到用户 ID
  • CometID,连接所在 comet 节点

Disconnect,断开连接,删除对应 Session 信息:

  • DeviceID,设备唯一 ID
  • CometID,连接所在 Comet 节点
  • UserID,用户 ID

Session,会话信息通过 Redis 保存连接路由信息:

  • 连接维度,通过 设备 ID 找到所在 Comet 节点
  • 用户维度,通过 用户 ID 找到对应的连接和 Comet 所在节点

Goim 长连接 TCP 编程 - Comet

Comet 长连接层,实现连接管理和消息推送:
Protocol,TCP/Websocket 协议监听;
Packet,长连接消息包,每个包都有固定长度;
Channel,消息管道相当于每个连接抽象,最终 TCP/Websocket 中的封装,进行消息包的读写分发;
Bucket,连接通过 DeviceID 进行管理,用于读写锁拆散,并且实现房间消息推送,类似 Nginx Worker;
Room,房间管理通过 RoomID 进行管理,通过链表进行 Channel 遍历推送消息;

每个 Bucket 都有独立的 Goroutine 和读写锁优化:

  1. Buckets { channels map[string]*Channel
  2. rooms map[string]*Room }

Bucket
维护当前消息通道和房间的信息,有独立的 Goroutine 和 读写锁优化,用户可以自定义配置对应的 buckets 数量,在大并发业务上尤其明显。
Room
结构也比较简单,维护了的房间的通道 Channel, 推送消息进行了合并写,即 Batch Write, 如果不合并写,每来一个小的消息都通过长连接写出去,系统 Syscall 调用的开销会非常大,Pprof 的时候会看到网络 Syscall 是大头。
Channel
一个连接通道。Writer/Reader 就是对网络 Conn 的封装,cliProto 是一个 Ring Buffer,保存 Room 广播或是直接发送过来的消息体。

内存优化主要几个方面

一个消息一定只有一块内存:

  • 使用 Job 聚合消息,Comet 指针引用。

一个用户的内存尽量放到栈上:

  • 内存创建在对应的用户 Goroutine 中。

内存由自己控制:

  • 主要是针对 Comet 模块所做的优化,可以查看模块中各个分配内存的地方,都使用了内存池。

SS 模块优化也分为以下几个方面

消息分发一定是并行的并且互不干扰:

  • 要保证到每一个 Comet 的通讯通道必须是相互独立的,保证消息分发必须是完全并列的,并且彼此之间互不干扰。

并发数一定是可以进行控制的:

  • 每个需要异步处理开启的 Goroutine(Go 协程)都必须预先创建好固定的个数,如果不提前进行控制,那么 Goroutine 就随时存在爆发的可能。

全局锁一定是被打散的:
-Socket 链接池管理、用户在线数据管理都是多把锁;打散的个数通常取决于 CPU,往往需要考虑 CPU 切换时造成的负担,并非是越多越好。

Goim 长连接 TCP 编程 - Logic

Logic 业务逻辑层,处理连接鉴权、消息路由,用户会话管理;
主要分为三层:

  • sdk,通过 TCP/Websocket 建立长连接,进行重连、心跳保活;
  • goim,主要负责连接管理,提供消息长连能力;
  • backend,处理业务逻辑,对推送消息过虑,以及持久化相关等;

Goim 长连接 TCP 编程 - Job

业务通过对应的推送方式,可以对连接设备、房间、用户 ID 进行推送,通过 Session 信息定位到所在的 Comet 连接节点,并通过 Job 推送消息;
通过 Kafka 进行推送消峰,保证消息逐步推送成功;
支持的多种推送方式:

  • Push(DeviceID, Message)
  • Push(UserID, Message)
  • Push(RoomID, Message)
  • Push(Message)

ID 分布式生成器

Goim 长连接 TCP 编程 - 唯一 ID 设计

唯一 ID,需要保证全局唯一,绝对不会出现重复的 ID,且 ID 整体趋势递增。
通常情况下,ID 的设计主要有以下几大类:

  • UUID
  • 基于 Snowflake 的 ID 生成方式
  • 基于申请 DB 步长的生成方式,例如拿到一批 1-1000 号给服务 1,拿到 10001-2001 给服务 2
  • 基于数据库多主集群模式
  • 基于 Redis 或者 DB 的自增 ID 生成方式
  • 特殊的规则生成唯一 ID

IM  私信系统

基本概念

在聊天系统中,我们几乎每个人都在使用聊天应用,并且对消息及时性要求也非常高;
对消息也需要有一致性保证;
并且都有着丰富的多媒体传输功能:

  • 1 on 1 (1 对 1)
  • Group chat(群聊)
  • Online presence(在线状态)
  • Multiple device support(多端同步)
  • Push notifications(消息通知)

IM 私信系统 - 聊天系统

在聊天系统中,主要是客户端和服务端之间进行通信;
客户端可以是 Android、iOS、Web 应用;
通常客户端之间不会进行直接通信,而是客户端连接到服务端进行通信;
服务端需要支持:

  • 接收各个客户端消息
  • 消息转发到对应的人
  • 用户不在线,存储新消息
  • 用户上线,同步所有新消息

IM 私信系统 - 实时通信协议

在聊天系统中,最重要的是通信协议,如何有保证地及时送达消息;
一般来看,移动端基本都是通过长连方式实现,而 Web 端可以使用 HTTP、Websocket 实现实时通信;
常用通信方式:

  • TCP
  • WebSocket
  • HTTP 长轮询
  • HTTP 定时轮询

IM 私信系统 - 服务类型

在聊天系统中,有着很多用户、消息功能,比如:
登录、注册、用户信息,可以通过 HTTP API 方式;
消息、群聊、用户状态,可以通过 实时通信 方式;
可能集群一些三方的服务,比如 小米、华为推送、APNs 等;
所以,主要服务可为三大类:

  • 无状态服务
  • 有状态服务
  • 第三方集成

IM 私信系统 - 模块功能

在聊天系统中,Goim 主要角色是 Real time service,实现对 连接 和 状态 的管理:
可以通过 API servers 进行系统之间的解耦;
各个服务的主要功能为:

  • 聊天服务,进行消息的 发送 和 接收
  • 在线状态服务,管理用户 在线 和 离线
  • API 服务处理,用户登录、注册、修改信息
  • 通知服务器,发送推送通知(Notification)
  • 存储服务,通过 KV 进行 存储、查询 聊天信息。查询聊天消息,mysql 存储用户,群组关系数据,每个消息都一个 seq 顺序 ID,能够种顺序索引

IM 私信系统 - 消息发送流程

一对一聊天,主要的消息发送流程:

  • 用户 A 向 聊天服务 发送消息给 用户 B
  • 聊天服务从生成器获取消息 ID
  • 聊天服务将消息发到消息队列
  • 消费保存在 KV 存储中
  • 如果用户在线,则转发消息给用户
  • 如果用户不在线,则转发到通知服务(Notification)

IM 私信系统 - 发信箱 / 收信箱

消息同步模型中,有 写扩散 和 读扩散 这两种模型。
主要有这两种概念:

  • 收件箱(inbox):该用户收到的消息。
  • 发件箱(outbox):该用户发出的消息。

Timeline 模型:

  • 每个消息拥有一个唯一的顺序 ID(SequenceID),消息按 SequenceID 排序。
  • 新消息写入能自动分配递增的顺序 ID,保证永远插入队尾。
  • 支持根据顺序 ID 的随机定位,可根据 SequenceID 随机定位到 Timeline 中的某个位置。

IM 私信系统 - 存储类型选择

在聊天系统中,消息存储是最主要的,通常会有海量的消息需要存储,我们也会想到 关系数据库 还是 NoSQL 数据库;
而关系数据库主要进行存储用户信息,好友列表,群组信息,通过主从、分片基本满足;
由于消息存储比较单一,可以通过 KV 存储;
KV 存储消息的好处:

  • 水平扩展
  • 延迟低
  • 访问成本低

IM 私信系统 - 消息存储设计(1 on 1)

在 1 对 1 聊天消息中,最重要的是数据格式,以及消息主键 messageid,需要保证一定的顺序,并且可以按规则 Scan PrefixKey。
消息数据模型:
messageid,消息 ID。
message_from,消息发送者 ID。
message_to,消息接收者 ID。
content,消息内容。
created_at,消息发送时间。
收件箱(Inbox),KV:
:
发件箱(Outbox),KV:
:

IM 私信系统 - 消息存储设计(Group chat)

在群聊中,存在读写放大问题,所以需要按具体场景考虑主键设计。
消息数据模型:
channelid,频道 ID。
messageid,消息 ID。
user_id,消息发送者 ID。
content,消息内容。
created_at,消息发送时间。
收件箱(Inbox),KV:
: (多读)
_ : (多写)
发件箱(Outbox),KV:
:

IM 私信系统 - 群聊 / 订阅号

群聊,较为复杂,通常有多写、多读两种方式;
单件箱(多写),每个用户都保存一份消息:

  • 消息同步流程比较简单,每个客户端仅需要读取自己的信箱,即可获取新消息
  • 当群组比较小时,成本也不是很高,例如微信群通常为 500 用户上限
  • 对群组数量无上限

多件箱(多读),每个群仅保存一份消息:

  • 用户需要同时查询多个信箱
  • 如果信箱比较多,查询成本比较高
  • 需要控制群组上限

IM 私信系统 - 读写扩散

一般消息系统中,通常会比较关注消息存储;
主要进行考虑“读”、“写”扩散,也就是性能问题;
在不同场景,可能选择不同的方式:

  • 读扩散,在 IM 系统里的读扩散通常是每两个相关联的人就有一个信箱,或者每个群一个信箱。
    • 优点:写操作(发消息)很轻量,只用写自己信箱
    • 缺点:读操作(读消息)很重,需要读所有人信箱
  • 写扩散,每个人都只从自己的信箱里读取消息,但写(发消息)的时候需要所有人写一份
  • 优点:读操作很轻量
  • 缺点:写操作很重,尤其是对于群聊来说

IM 私信系统 - 推拉结合模式

在长连接中,如果想把消息通知所有人,主要有两种模式:一种是自己拿广播通知所有人,这叫“推”模式;一种是有人主动来找你要,这叫“拉”模式。;
在 IM 系统中,通常会有三种可能的做法:

  • 推模式:有新消息时服务器主动推给所有端(iOS、Android、PC 等)
  • 拉模式:由前端主动发起拉取消息的请求,为了保证消息的实时性,一般采用推模式,拉模式一般用于获取历史消息
  • 推拉结合模式:有新消息时服务器会先推一个有新消息的通知给前端,前端接收到通知后就向服务器拉取消息
  • 消息同步模型
    • 收件箱模式:该用户要收到的消息: ```
  1. 读扩散,我有100个群,需要捞100个群ID和消息ID,得到消息看到哪里来了,把剩下同步回来
  2. 写扩散,100的人,写的时候直接写道userID+messageID的组成的key,直接写向这100人,上线后直接拉取回来即可 ```
  • 发件箱模式- 该用户发出的消息
    • 消息推送模式
  • 推模式
  • 拉模式
  • 推拉模式,推一个消息事件,打开去收件箱去拉,建议这种模式

References

https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-netpoller/
https://www.liwenzhou.com/posts/Go/15_socket/
https://hit-alibaba.github.io/interview/basic/network/HTTP.html
https://www.cdn77.com/blog/improving-webperf-security-tls-1-3
https://cloud.google.com/dns/docs/dns-overview?hl=zh-cn
https://cloud.tencent.com/developer/article/1030660
https://juejin.cn/post/6844903827536117774
https://xie.infoq.cn/article/19e95a78e2f5389588debfb1c
https://tech.meituan.com/2019/03/07/open-source-project-leaf.html
https://mp.weixin.qq.com/s/8WmASie_DjDDMQRdQi1FDg
https://www.imooc.com/article/265871
https://www.infoq.cn/article/the-road-of-the-growth-weixin-backgroundhttps://systeminterview.com/design-a-chat-system.php
https://blog.discord.com/how-discord-stores-billions-of-messages-7fa6ec7ee4c7
https://www.facebook.com/notes/facebook-engineering/the-underlying-technology-of-messages/454991608919/
https://www.infoq.cn/article/the-road-of-the-growth-weixin-background
https://slack.engineering/flannel-an-application-level-edge-cache-to-make-slack-scale/
https://www.infoq.cn/article/emrual7ttkl8xtr-dve4
http://www.91im.net/im/1130.html
https://xie.infoq.cn/article/19e95a78e2f5389588debfb1c