今天我们来解读《从无到有:微信后台系统的演进之路》,这是微信团队张文瑞分享的一篇博文。
微信的基本模型是什么?
微信是一个从发送者将消息发送到微信后台,然后发送给接收者的过程。
最简单的发送模型甚至连微信后台都不需要,但由于很多逻辑需要处理,所以慢慢有了微信后台。
当然,有了基本架构以后还会出现很多问题。
  • 接收者不在线怎么办?
    此时需要把消息存储在后台里。
  • 每次直接推送消息代价很大怎么办?
    大家用微信会发现人们不是每次立刻读取消息,所以没必要把消息都写到本地,可以把带宽节省给在线的人推送消息。因此我们只需要推送通知,告诉你有新的消息。
  • 如果推送通知,需要接收者主动拉消息
    运用下发消息的模块。
微信后台的数据有哪些?
为了能够使用,需要账号信息;为了跟好友聊天,需要联系人信息;最后需要传输最重要的消息,所以这三个是最基本的数据。
如何同步数据?
最简单的方法是版本号。在每次增加或更新数据的时候,多加一个版本号,以后只要比对数字就可以。并且可以针对前边的三部分数据,分别设置版本号,简化数据的更新。
后台架构是什么?
最基本的是一些业务逻辑,比如发短信、收短信等这些只需要一个服务器,但随着业务的增长,还需要一个数据存储服务来提供数据的存储及数据封装的操作,再进一步,对外会有一个接入服务来获得用户请求。有接入服务以后,我们需要把数据访问和数据存储再切开。底层是数据最基本的存储,上层是能够访问数据的各种逻辑接口。再进一步,我们还可以把业务逻辑拆解成基础逻辑(实现过程的基本元素)和高层的业务逻辑。这样最上层是接入层,中间是逻辑层,底层是存储层。
如何支持群聊?
因为从张三发消息到李四是很简单的单聊消息,我们可以通过一些同步操作来执行。但当你碰到群聊消息时,通常要发送很多消息,那就不能在那等待,不然会卡死。所以我们往往会进行一个异步操作,这时候同步操作已经不够,或者latency太大,于是我们逐步地加入异步操作,来解系统的耦合。
群聊是Pull还是Push?
这个群聊消息应该推(Push)给王五、赵六,还是王五、赵六主动去拉(Pull)呢?实际上,最简单的方法是当你的接收者特别多时,肯定是(Pull)方式比较好,因为Push(推)这么多人代价会比较高。但是当接收者比较少的时候,推(Push)就比较好,因为毕竟都存好了比较方便。微信恰恰是一个群人数有限制,一般群上限有500人,当然还是推(Push)比较好。
服务架构如何设计?
有各种各样、成百上千的服务,应该怎么样组合呢?那就需要我们之前文章提到的微服务架构。微服务有两块,上面的一块是它的接口,下面一块是它的具体服务,比如消息同步服务,文本语音发送服务,可能还有图片视频发送服务等。
所有这些服务都可以提供统一的HTTP接口,可以做成长链接,也可以做成REST。这个架构就是一个微服务架构,它们把服务之间耦合起来。但在设计初期需要微服务吗?并不一定需要,微信刚开始也是统一的服务接口捆绑到一起,之后发展越来越大,才会做这种微服务设计。
如何监控服务?
我们要把后台服务的数据统一起来,发送到一个终端或某个地方收集起来进行统计。但这个模块往往很复杂,统计其实是把一个数字给记下来,可以有两种操作:设置一个值,或增加一个值。所以我们可以在后台启动一个子服务,统计服务的进程。它在共享内存里帮助两个API,Site和Ad,让大家能够统计数据。
数据在本地的Agent收集到以后,每隔一定时间就可以上传到远程的控制中心,而这个控制中心会统计出这样的控制数据。因为有成百上千的这种服务,可以把它们数据捆绑到一起去做。有这个控制数据以后,就可以上传展示,包括出问题以后发短信、发邮件报警。
储存架构是什么?
最简单肯定是一个Master的数据节点。之后如果发现Master不行再增加一个Slave,Slave跟Master同步。最早,Slave只能在Master挂掉以后手动替换;后来可以做到自动切换;之后,Master写的同时Slave可以更新(Update);再往后,可以有多个Slave跟Master同步;当然,我们还可以进一步用选举算法,多个Master之间通过一些方法,比如版本号的方式来同步数据,实现多个服务同时提供服务的方式。
如何实现海外加速?
左边是国内的上海服务中心,会有用户的接入服务来服务所有用户。但是也有很多国外用户需要提供服务,如果都连到国内,就会变得特别慢。于是就想到在国外也有一个数据中心。但是要怎么同步呢?这就要用到雅虎的PNUTS算法。
简单理解就是:国内的人访问国内,同步数据;国外人访问国外,作为宿主访问这里,但同时有两个同步服务:国内的服务写进去以后,不仅放在存储里,还放在一个队列里,这个队列不断把国外的数据发送到国内,然后通过数据访问服务存储起来;而国内也是一样,如果你的数据在本地写了以后,也通过这个队列Push到远程,然后再由远程把数据对应到队列里。Pull这个过程很重要,可以防止数据不丢失。
那怎么同步呢?可以有多台机器,比如三台。三台机器都需要同时保证正确吗?也不一定,通过选举算法保证两台正确就可以。那怎么保证数据的顺序性呢?加版本号就可以。
如何容灾?
如果只有一个数据中心,比如上海数据中心崩溃就全部坏了。
比较好的是有两个数据中心,各提供一半的服务能力。如果都提供100%的服务能力,一个中心崩溃了那另外一个也撑不住。
更好的方法是有三个数据中心,每个提供66%的服务。任何一个服务器崩溃,都可以把数据或压力推给剩下的两个服务器。数据中心越多,看似很好,但实际数据同步也越麻烦。保证每个数据至少在两个数据中心有存储,这样就不会出问题。
如何防止雪崩?
当服务器C正在运行,服务器B在连接服务器C,并且不断地等待重试,如果服务器C变得非常缓慢,那B就会不断地重试,不断地等待,于是服务器B堆积的服务也会越来越多;同时服务器A也在等B,它也会不断的重试,不断地等待。如果此时服务器C崩溃,那服务器B也会崩溃,因为它会被请求堆满;接着服务A也会崩溃。
那要怎么办呢?可以快速拒绝。当你的访问量到达一定请求的时候,就不要再接受,把它全部拒绝就可以防止雪崩。
总结
  • Twitter与微信历史相似,学会一步步长大。
  • 监控服务的累加设置模型
  • 双数据中心的PNUTS备份模型
参考文献:
《从无到有:微信后台系统的演进之路》
Chris老师带你理解JAVA多线程的编程模式,并能够熟练地开发JAVA多线程应用,了解多线程在大数据系统中的应用。
↓↓↓
继续阅读
阅读原文