Thinking PostgreSQL PL/Proxy Used in weibo(微博) Case

最近和网络的同事聊组播的技术,对于IP电视来说,这个技术可以大大降低网络的开销。
突然想到微博其实也是很耗带宽的一种东西,之前也没去了解过,我的理解是微博就类似留言,留言上带上了撰写人,标签,是否公开,接收人,发送时间等属性。
如 , 
普通的一条微博,有了撰写人,那么关注撰写人的用户在登录微博时就需要看到这部分微博信息。
另外,也可以定点给某人或者某些人发送信息,那么就有了接收人的属性。

如果用户量很大,活跃用户比较多的情况下,信息量也是巨大的。特别是明星用户。关注或被关注的人比较多的情况下。信息推送都会带来比较大的流量。

组播就值得借鉴了,如在10毫秒内发起的请求,如果有相同的,只请求一次。

另外,为了获得好的扩展性,数据库设计的时候要充分考虑数据暴增带来的问题。
如下:
Thinking PostgreSQL PL/Proxy Used in weibo Case - 德哥@Digoal - The Heart,The World.
 
发微博为了提高响应速度可以考虑异步消息,记录撰写人的USERID,私信接收人的USERID,如果是回复的话记录子msgid等属性。
MQ异步写入到索引库和消息数据库。

热索引主要用来存储收微博时需要用到的索引,如根据关注者的USERID(s)来检索msgid,根据自己的USERID来检索MSGID(私信),根据标签来检索MSGID。

索引库和消息数据库都可以使用PostgreSQL数据库,使用PL/Proxy可以不用担心数据库的扩展能力(读用流复制扩展(毫秒延时),写用bit&分库扩展)。
PostgreSQL的pgfincore插件能实现数据文件块级别的内存映射,并能记录下数据块的位置,重启之后通过位置信息进行预加载数据或索引数据至内存,非常灵活。(灵活性超越ORACLE的buffer pool keep)
写能力的提高除了分库之外,单库写能力的提高也可以使用异步事务提交, 分组提交等。

持久数据(历史数据), 每日/小时从热数据库同步。热库定期删除时间比较OLD的数据。

收微博的时候,到关系库取出关注者的userid(s),根据关注者的USERID检索索引库,按时间倒序取出MSGID。然后根据msgid(s)去数据库取出数据。

收取私信的时候,根据自己的USERID到索引库检索MSGID,按时间倒序取出MSGID。然后根据msgid(s)去数据库取出数据。

如图 : 
Thinking PostgreSQL PL/Proxy Used in weibo Case - 德哥@Digoal - The Heart,The World.

热数据和热索引在这里只的是时间比较接近当前时间的数据,怎么理解呢?
因为微博里面的信息量非常大,推送给用户的时候是按照时间倒序显示的。所以时间约新鲜,数据越热。被回复和转发的概率越大。
而时间比较久远的数据,相对来说不太会被查询或修改。

Thinking PostgreSQL PL/Proxy Used in weibo Case - 德哥@Digoal - The Heart,The World.
分库规则:
1. 索引库分库因子: userid(int8) bit& 操作, attr(int4) bit&操作.库的个数为2^n次方。当然plproxy允许重复条目。所以最粗的时候服务器不需要完全按照实际分库的个数来配置,可以后期几乎平滑的扩展。
2. 数据库分库因子: msgid(int8) bit& 操作, 库的个数为2^n次方。当然plproxy允许重复条目。所以最粗的时候服务器不需要完全按照实际分库的个数来配置,可以后期几乎平滑的扩展。
3. 关系库分库因子: userid(int8) bit& 操作。当然plproxy允许重复条目。所以最粗的时候服务器不需要完全按照实际分库的个数来配置,可以后期几乎平滑的扩展。

CACHE:
pgmemcached, 通过这个PostgreSQL插件,CACHE操作可以更加灵活的和数据库紧密结合起来(通过PG函数增删改查memcache的内容)。
Thinking PostgreSQL PL/Proxy Used in weibo(微博) Case - 德哥@Digoal - The Heart,The World.
 

关系库:
正向数据结构 : userid(int8),attention_userid(int8) 。(是否需要限制关注上限,关注的人越多,每次获取关注人信息的数据量越庞大)
反向数据结构 : userid(int8),attentioned_userid(int8) 。(明星用户可能被百万甚至千万人关注)

其他:
按USERID来分库 ,在数据库的扩展性方面比较灵活。
当然还要考虑msgid取出的时候需要merge后排序,这个比较麻烦。

按时间来分库比较麻烦的是,热点将集中在最近的库。
按时间,然后在下面再按用户ID来分,或许也是一种选择。

【能力预估】
假设 1台8核72G内存,500G硬盘服务器, 1.5W rw tps. 
        缓存服务器, 15W rw tps.
用户1亿,平均关注100用户。正向关系100亿,反向关系100亿。
10%活跃用户。平均每人每天发微博10条。一天1亿条新增微博信息。
关系库预计投入:100/8=12.5 台, 对外提供18W rw tps
反向关系库预计投入:100/8=12.5 台, 对外提供18W rw tps
(每一维度)热索引库预计投入:2/8=1 台, 对外提供1.5W r/w tps (可能不能满足rTPS要求,通过复制或者pgmemcache解决)
热数据库预计投入:2/1=2 台, 对外提供3W r/w tps (可能不能满足rwTPS要求,r通过复制或者pgmemcache解决,w增加分区服务器或者MQ异步消息解决)
(每一维度)历史索引库预计投入:视存储量
数据库预计投入:视存储量
缓存服务器预计投入:视实际请求量
hot standby服务器预计投入:视实际请求量

【压力测试】

有待完善.