Facebook之前上线了新的messages实现,以前草草的看过相关的几篇blog还有facebook同学在qcon上讲的hbase的slide,但其实看的都很粗略,尤其是之前去facebook和相关同学交流后,发现和自己之前理解的太不一样了,于是近几天又翻出了messages的几篇blog来仔细的看了看,看完后的感触就是facebook在设计其messages实现时,会尽可能做到物尽其用,对于不满足的则更多的是在应用层来处理,这样可以保证很好的灵活性以及扩展性,下面就来讲讲我现在理解的facebook messages实现,请各位看官拍砖,:)

Facebook的这套新的messages实现用于email/sms/即时聊天等多个场景中,大附件或大内容的存储使用haystack(Facebook用其来存图片),小数据则在N次对比(MySQL、Cassandra和HBase)后选择了hbase,结合hbase的特性,facebook设计了如下的schema:


表名未知,:),maybe是usermetadata,单个用户的数据存储在同一行中(多个版本),有4个cf:
1、Action Logs
记录用户messages的变化日志,同时也将有利于实现跨表的事务问题,版本为时间戳,在将旧的inbox的数据迁移到新的messages时,facebook的做法就是根据旧的数据形成了actionlogs,然后再用mapreduce直接写入hbase,而它提到的另外一点好处就是,如果将来metadataentities/indexes要改的话,也只需要reply action logs就行了。
2、Metadata Entities
记录metadata的实际信息,例如threads、messages信息,版本为action logs的id。
3、Metadata Indexes
记录metadata的索引信息,以k/v方式为值,例如已读的、未读的等,版本为action logs的id。
4、Keyword Search Index
根据lucene parse出来的结果存储的keyword –> message的索引,每列就是一个keyword,版本为messageId。
在这个设计中,facebook很巧妙的借助了hbase的{rowkey,cl,version}的有序存储来实现业务的需求,另外为了避免hbase随机读的弱点,facebook设计了一层cache来尽可能减少对hbase的查询。

为了能够统一的支撑各种message场景,facebook设计了一层app serverlogic来支撑,facebook将cluster划分为了多个cell,每个cell负责一部分用户的请求,cell中的多台服务器按照一致性hash来组成,之所以这么设计一方面是为了保持比较好的扩展性,另一方面则是围绕hbase的特性来打造的,为了实现一致性hash以及帮助app端某用户应该到哪台服务器上处理,提供了一个discoveryservice,这个service基于zookeeper来实现,cell中每台server在启动后会向zk注册,discoveryservice会注册一个zk的watcher,这样discovery service就知道server的变动状况了。

当用户发送一条message时,会经过这样的过程:
1、访问discovery service,获取处理当前用户的appserver node;
2、向appserver node发送请求,appserver node会相应的将message的大数据存储到haystack上,组装message并存储,并根据message的类型调用相应的处理器进行后续处理。

当用户收到一个message时,会经过这样的过程:
1、解析message,提取大数据部分存储至haystack;
2、访问discovery service,获取处理此用户的appserver node;
3、在hbase中存储对此用户的action log以及message的small bodies;
4、以前facebook采用的是根据actionlog异步刷入hbase,原因是之前index/entities表里都是粗粒度的schema,同步刷的话比较浪费,现在则逐渐改为细粒度的schema了,所以就可以同步写了index/entities和keyword search index了;
5、dirty掉memcache上的一些信息,例如未读的message数。
用户可能会同时收到多条message,那么其中有几个部分就必须有事务的支持了,由于任何一个用户在某一时间内都只会在固定的一台server上处理,因此facebook的做法就是在app server上来保证事务的问题。

当用户访问inbox时,会经过这样的过程:
1、访问discovery service,获取处理此用户的appserver node;
2、查看本地cache中是否有user的active metadata(第一页会直接cache),有的话就直接进行必要的indexjoin,获取到对应的数据,返回,没有的话就去hbase中装载并放入本地cache,blog上的数据表明,app cache大概能cache5%–10%的users,由于facebook的用户不是同时使用,而使用者基本有一定的黏性,因此cache的命中率差不多能到95%。

当用户根据keyword搜索一条message时,会经过这样的过程:
1、访问discovery service,获取处理此用户的appserver node;
2、访问keyword search index列,获取top n的messageId,由于hbase存储的有序性,这个性能还是不错滴,然后从cache的active metadata中获取实际的信息。

为了防止大家被误导,原信息请大家查看以下的参考资料。
参考资料:
1、See the Messages that Matter
2、The Underlying Technology of Messages
3、Scaling the Messages Application Back End
4、Inside Facebook Messages’ Application Server
5、Hbase @ Facebook,The technology behind messages