我们每天的生活都离不开微信。微信基本上已经成了在中国生活的一部分。

但是,微信有些方面的功能总是看起来令人觉得有些奇怪。例如:

从产品的角度来看,这些设定看起来彷佛是在给用户制造障碍,也成了大家普遍对微信的槽点。那么,微信的团队为什么要这么设计,而为什么又不改良它的体验呢?我想或许问题并不只是产品和需求分析这么简单,而是还需要进一步探寻架构上的本质。

在我生活在澳大利亚期间,我发现一件很有趣的事情:在澳大利亚,我使用微信给同样在澳大利亚的好友发送微信消息,他也可以几乎瞬间收到。假想微信在国内建立单点的服务器,那么这种性能一定不足以支撑澳大利亚内的通信。数据从澳洲抵达中国再从中国推送到澳洲至少需要500ms。而表现来看,仿佛只花了30ms就完成了一条微信消息的传递。

那么这意味着这条消息很可能根本就没有去中国,而是只在澳大利亚当地就完成了收发和传递。微信在澳大利亚是单独部署有计算节点的。而这么来看,微信的服务器,应该是遍布全球各地,并没有一个中心化的服务器。微信是个分布式应用。

如果微信是分布式应用,对上面几个现象就不难解释了。但是我这么猜测,必须还得建立一套完整的可行性验证,并且能够满足现有微信的所有用例,我的这个猜想才算没有错误。而为了满足完整的分布式通讯,微信至少要设计三个算法:

这三个算法,第一个服务器选择算法,可以让一台微信移动端的App定位到最合适的微信服务器。服务器端切换算法可以实现在原有服务器不再可用时,平滑的移动到新服务器上并且继续保持消息。用户发现算法则可以搜索出目标用户所在的服务器。在这三个算法建立完善的基础上,用户可以直接定位到自己需要连接的目标微信服务器,并且目标微信服务器也知道你要将消息发送的目标用户所在的服务器,然后在两台服务器之间直接点对点通信即可。

服务器选择算法

微信的服务器为了扩展方便,他们可能会在全球各地建立大量微信节点,保证任何一个地理位置的人,都有一台离他不算太远的微信服务器可连。但是,即使硬件上保证了这一点,那目标节点的用户怎么才能得知这台离他不远的服务器的IP等信息,并且知道这台服务器最合适呢?服务器选择算法中,首先就得包含一个服务器的注册与发现。而在没有中心节点的情况下,要想维持一份数据,普遍的做法是采用gossip协议。

gossip协议是一种基于流行病传播方式构建的信息交换协议。它的原理是想象将我们需要传递的信息就是一种病毒,而这种的病毒R0 > 1,从而它让每个个体在被感染后都平均能够再传播超过一次。那么随着时间变化,所有个体都会感染这种病毒。这种协议的优势在于去中心化,是一种分布式协议,能够在一个集群中解决传播的状态一致性问题。换句话说,如果微信有一个“可以使用的微信服务器列表”,那么每新增一台服务器,这台服务器就可以向集群传播自己的信息,而这种信息很快就会“感染”所有的微信服务器,保证最终的数据一致性。最终,每一个微信服务器都能得知完整的可用服务器列表。这向技术,也普遍应用在了DNS记录的传播。

例如微信使用gossip协议维持了一份服务器清单,那么对于设备来说,只需要查询任意一台服务器就可以得到服务器列表。根据设备IP它不难得知自己的地理位置是在哪个国家哪个省,从而筛选出省内的服务器列表。再对这些服务器进行测速,或者搜索这些服务器中连接数最小的那个,就可以确定这台微信App需要连接的目标微信服务器了。

服务端切换算法

服务器选择后,我们还需要考虑目标服务器本身可能出现故障的情况,或者微信可能会撤走一台服务器。如果微信真的撤走了一台服务器,需要立即重新进行服务器选择。此时App端不再能够连接到撤走的那一台,而连接到另一台可用的好服务器上。