IM Architecture

来源:互联网 发布:优化速度插件下载 编辑:程序博客网 时间:2024/05/05 01:47

微信使用的越来越广泛,我们来聊一聊如何设计微信后台架构。我们从三个方面入手:

  1. how to communicate?(网络层)

  2. how to store data?(数据层)

  3. how to build API?(逻辑层)


1. how to communicate

1) how to communicate between two users?

微信最基本的功能是聊天,本质是两个用户的沟通。如何连接互联网上的两个用户?


有两个用户user 1user 2希望互相通信,user 1如何知道user 2在哪儿呢?传统的TCP连接需要IP地址。但在网络user 1如何知道user 2的地址呢?我们可以引入server,做为两个用户约会时的见面地点。试想最开始的时候,clientclient之间可以直接连接,而不需要其他媒介。但是随着client的增加,我们需要一个共享数据的中转站,而server能够帮助client来共享数据和资源。比如DNS serverclient识别各种URL对应的IP地址,communications server能够帮助user或者设备终端进行通信。

(详见wikipedia: https://en.wikipedia.org/wiki/Server_(computing)


我们一定要用server吗?不一定,我们可以用P2P模式。P2P (peer-to-peer) 模式把任务和负载分给一个个peer(网络上的节点,也是p2p网络形成的基本单位,每一个peer都有独特的peer ID)。不同于client-server模式,P2P中的每个peer不仅是资源的提供者,也是资源的消耗者。换言之,每个节点既是client,又是server。而在client-server的集中式的管理模式中,资源的消费和提供者往往是分开的。


有两种群消息分发模式:一种是pull,一种是pushPush模式在收到一个用户发出的消息后,会将消息直接扩散到每个群用户的消息列表中。Pull模式在收到一个用户发出的消息后,会将消息保存在频道的列表中,因此每个群用户需要主动进入这个消息列表中拉去自己需要的消息。

微信使用的是第二种方式,它的缺点是当群用户数量大的时候,开销较大,幸运的是微信群是有人数上限的。


2. how to store data? 

1) what data need to be saved?

微信有三种核心数据:accounts/contacts/messages。每一种都可以使用单独的方式保存。


那么对应每种数据,使用SQL存储还是NoSQL存储?实际上,绝大部分数据既能使用SQL,也能使用NoSQL。对于account信息,可以选择MySQL,因为较为稳定;对于contactsmessages,可以使用NoSQL存储。


2) why do we need memory?

Disk容量大,持久保存,但是因为读写涉及到磁盘的机械运动而速度较慢。因此我们引入memory来进行补足,它缓存了我们需要频繁访问的数据信息,因此当我们进行较复杂的join类操作时可以直接从memory中取数据,性能能够提升10倍以上。现在的工业界,1TB的数据基本都可以在memory中解决。


3) is one data center enough?

一个数据中心是不够的,原因不在于数据量大,而在于多数据中心的容灾(例如挖断光缆),和数据的就近访问。


一个架构是有三个数据中心,每个中心都有全数据,承接2/3的负载。当一个数据中心不能正常工作了,它的负载会转移到另两个数据中心。


4) how to monitor the number of registered/online users?

注册用户可以直接在MySQLcount。在线用户可以通过log,上线+1,下线-1。这里需要注意的是用户超时退出的情况


5) how to connect?

如果一个用户知道了另一个用户的信息,他们是如何建立连接的呢?现实中我们可以发邮箱,打电话在网络中,发短信对应短连接(short connection),打电话对应长连接(persistent connection)。前者在每次联系的往返都要建立一次连接,而后者可以持续一个较长时间的连接。


长连接:指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接;一般需要自己做在线维持。短连接:指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接。


通常的短连接操作步骤是: 

连接数据传输关闭连接;

而长连接通常就是: 

连接数据传输保持连接(心跳)→数据传输保持连接(心跳)→……→关闭连接; 

(参考:http://blog.chinaunix.net/uid-26000296-id-3758651.html


6) how to save traffic?

长连接可以节省建立链接的流量,除此之外我们还能通过批量发送和数据压缩来节省流量。


批量发送是指将一堆信息一起打包传输。这个在消息特别频繁的时候较为有用。


P2P模式也能够省服务器流量。因为P2P可以在client之间传递信息。随着我们的带宽环境越来越好,P2P省的流量越来越不显著,而它不稳定的缺点却越发明显,所以我们可以感觉到P2P并没有之前那么火。


推拉结合的模式(pull-push)也能省流量。当AB发送消息,B可能无需立刻读取,比如他正在开会。那么只需提醒B有新消息,而这些消息不用立刻发给B。在实际的微信中,头像右上方常常有个小红圈显示有多少个新消息,这些新消息并没有存在client端,只有当用户打开微信读取的时候,消息才实际传输过来。此过程中B就是在拉取信息;因此我们推的只是消息数量,而之后再拉去消息。这种推拉模式下,数据很容易被批量打包。


7) what is sync between users and servers? 

clientserver需要同步什么信息?微信最基本的是accountmessagecontact。如何保持数据的同步呢?比如微信有手机版和网页版,用户手机里新添加了一个联系人,他希望网页版也能看到这个联系人信息。


解决这个问题,需要针对数据标记timestamp,从而能够得知本地数据是否过期。但是不同的设备的timestamp也许是不准确的(设备本身的时间也许不准)。因此可以使用逻辑时钟。逻辑时钟相当于版本号,v1v2v3……


3. how to build API? 

把整个架构理解为一座冰山,API是浮在水面上的一角,系统通过它与用户沟通。


1) how to handle a user's request?

我们要思考,clientr会有哪些请求呢?例如:

1send message

2edit account

3read message

4 Red packet

5log in/out

6moments


可以分类为聊天相关、账号相关、feed流相关。

Feed火于rss年代,google reader通过读一个网站的rss信息,获得该页面是否更新,rss里产生的消息叫做feed


2) how to write less code?

作为程序员,我们希望能够用简约的代码实现丰富的功能,这使我们想到代码的模块化复用。也与OOD的思想相通。


API可以分层:业务层API(用户能访问到的层,比如修改备注等),基础API(提供更抽象的功能)。基础API有两类:基础逻辑APIData APIData API为了能更好的处理data,比如有memory cache等等。在微信里,基础逻辑APIData API是并行的。如何考虑两个层是并行还是串行的呢?从业务API来看,如果它既能够访问逻辑API,又能访问Data API,那么这两层是并行的,反之可以是串行的。究竟是并行好还是串行好,这里并没有一个最好的方法,只有最适合的方法。


回到冰山的例子。API是上面显露的部分,水中的部分是一个个logic module。在传统的CGI模式中,有一个container包含所有ogic module。当用户通过API调用数据时,container决定哪个logic module处理这个请求。


这个模式有很多缺点,包括单点故障,连带效应,耦合等等。比如说一旦container出现问题,整个系统将不能正常工作,或者某个模块出现故障,整个container也可能崩溃。


解决这些问题的基本想法是拆解,降低它们的耦合度。micro-service就是基于这个思想,降低模块之间的关联度一个故障并不影响其他模块。每个模块之间可以通信。并我们可以有一个master掌管这些模块,也可以有很多个master。有的负责聊天相关的功能,有的负责图片相关的功能。这和数据库里的shard思想也有些神似。


3) how to log

对于程序运行时的log统计,是个辛苦的工作,尤其是在分布式的环境中。

微信搭建了一套分布式的log框架,在每个机器有一个进程统计数据,比如error count。机器里的其他进程都能通过简单的API往这个进程写数据,比如error count++。这样只需要一行代码,就实现了log的统计。这些log进程再定期往一个master里传递数据即可。从而大大简化了分布式系统的debug工作。


由于时间关系,我们无法设计所有技术细节,只能提供一个大体的思路。但正如上一次talk show里所说,技术是由需求和瓶颈驱动的。在设计系统时,我们要考虑到用户的需求是什么,如何满足这些需求,有什么更好的解法从而一步步找到适合我们的答案。


0 0
原创粉丝点击