需求定义

朋友圈的核心是每个用户各自拥有的一个自己发布的相册和一个用户关注的好友的动态,称之为时间线TimeLine。为了实现这两个功能,存储系统的设计需要考虑如下需求。

  • 需要知道哪些用户关注了LiLei以使得这些用户能够看到LiLei的朋友圈。
  • 需要知道 LiLei关注了哪些用户以计算LiLei能够看到Lucy朋友圈的哪些评论。
  • 为了保证用户体验,LiLei的朋友圈打开速度要求很快。

需求分析

1. n用户 (关注) -> LiLei -> 朋友圈
2. LiLei (关注) -> Lucy -> 朋友圈评论
3. 1和2的运算要尽量的快

被关注:关注当前用户的用户
关注:当前用户关注的用户

初次设计

按关系型数据的直觉 , 这种一对多的关系 , 我们会设置两个表

  • 表一 t_user 表

    • RowKey(行键):用户唯一标识符
    • 列族(Column Family,cf):包含列名
    • :用户的名称信息
RowKey列族(cf)列用户名 (n)
12345cfLiLei
12346cfLiLy
12347cfLucy
12348cfHanMeiMei
12349cfTom
  • 表二 t_following 表

    • RowKey(行键):表示用户ID
    • 列族(Column Family,cf):存储关注的用户ID
    • :动态列,列名为不同的标识
RowKey列1列2列3列4
12345123461234812349...
123461234812349
1234712346

这种设计的典型的Hbase中的宽表,利用列族和动态列来存储稀疏数据。

这种设计的方案有一个比价明显的问题t_following表每一行的值代表的是当前用户关注的用户,没有当前用户被关注的信息,如果要获取关注当前用户的信息,我们需要扫描所有的表才可以获取到结果,这样设计是不合理的。

解决无法O(1)获取到被关注

  • 表一 t_user 表:不变

虽然宽表每行中能表达的含义更加丰富,但是无法满足查询被关注的业务,希望t_following表中需要包含关注的信息并且有被关注的信息,这种信息能通rowkey去精确获取。

这种设计下,行的含义不再需要非常丰富,而rowkey的含义需要丰富到能通过rowkey获取到关注和被关注的信息。

  • 表二 t_following 表

  • rowkey可以设计为:用户id+状态+用户id

    • 状态:关注/被关注
行键列族(cf)n
12345_0_12346LiLy
12345_0_12348HanMeiMei
12345_0_12349Tom
12346_0_12348HanMeiMei
12346_0_12349Tom
12346_1_12345LiLei
12346_1_12347Lucy
12347_0_12346Tom

设计朋友圈相册表

  • t_album 表格
    • rowkey:用户id+时间戳
    • t是朋友圈的信息
    • p是图片的CDN缓存
行键列族(cf)tp
12345_时间戳发送1110.1的1条朋友圈http://url5
12346_时间戳发送1110.1的2条朋友圈http://url4
12347_时间戳发送Lucy的朋友圈http://url3
12348_时间戳来自HanMeiMei的消息http://url222
12349_时间戳Tom向你同步http://url1

时间线设计

时间线存储的是某一个用户关注的用户发送的朋友圈

  • t_timeline 表格
    • rowkey:用户id+时间戳+发布的用户
    • t是朋友圈的信息
    • p是图片的CDN缓存
    • u是用户信息
行键tpu
12345 1521708554262 12348来自HanMeiMei的消息http://url4HanMeiMei, http://picurlHanMeiMei
12345 1521708554263 12349Tom向你问好http://url5Tom, http://picurltom
12346 1521708554262 12348来自HanMeiMei的消息http://url4HanMeiMei, http://picurlHanMeiMei