人人网UGC海量存储系统Nuclear介绍 – 功能应用篇

作者:人人网技术民工 冷昊 人人网UGC团队博客

书曰:工欲善其事,必先利其器。人人网作为国内第一大SNS网站,欲存海量UGC数据,必有海量存储系统。Nuclear存储系统在高性能、高可靠、可扩展的海量数据存储需求下横空出世,待小的给列位看官慢慢道来。

缘由篇

看过《人人网使用的开源软件列表》一文的看官一定知道人人网的关系型数据库使用的是MySQL,Key-Value存储使用的是Tokyo Cabinet,话说战斗在第一线的UGC Team的兄弟们发现,MySQL虽然已经被我们用上了散库、散表大法,但是每次数据达到服务器负载临界值时,必然得经过一番迁移数据的剧痛;使用TC也会存在这个问题,且TC只在某些特定的应用场景起作用。于是乎,我们开始需找能满足高性能、高可靠、可扩展等特性,同时能符合UGC应用场景的存储系统,下表列出我们的考察对象及需求。

Snap2

TC在使用过程中发现单独使用TC会在某些时间点出现性能瓶颈;Voldemort目前的版本对扩展性支持不好;且Voldemort和Casscandra作为一个正在快速开发中的系统,我们尚未有勇气把它引入到生产环境中。追溯到Amazon的Dynamo系统,我们决定在其思想上开发自己的存储系统,Nuclear就是在这样的背景下诞生的。言归正传,给各位道来功能篇及应用篇。

功能篇

高可扩展

一个Nuclear集群支持1到n(n<264)个节点(Node)的规模,每台服务器(Server)支持部署多个节点。当集群资源达到瓶颈时,可以通过增加新的节点来扩展。增加新节点的过程,系统服务无需停止,无需人工干预迁移数据。Nuclear理论上可以无限Scale-Out

高可靠

单个节点的crash永远对系统的运行造成影响,不存在单点风险。数据的写入参考Dynamo的W+R>N理论,简释之,例如设置系统每一份数据都存储在3个节点上(N=3),那么读的话必须成功读到两个节点上的数据才认为读成功 (R=2),写的话必须成功写到两个节点上才认为写成功( W=2)。系统永远可写入(Hinted HandOff)。

高性能

在Xeon E5405 CPU的服务器上,单节点每秒最高2.5w req/s。整个集群的性能取决于一致性级别、N、W、R数及底层存储引擎的选择。例举我们的一个测试数据:
节点数量:4 Node (Server配置: Xeon E5405,16G memory,千兆网卡)
存储引擎:Mysql5.0.45
参数:N=3 W=2 R=2
压力:100 Client Write Request
测试结果:单个Node 15862 req/s,从Client看平均单次请求耗时5ms(见图), 99.51% 请求耗时 < 50ms

nnn1

存储

Nuclear本身的数据存储是基于Key-Value形式的,value的形式可以是富数据模型,也可以是List;如果底层的存储引擎是关系型的,那么Nuclear还提供弱结构化的查询功能。下面是Nuclear目前及计划中支持的存储引擎。

fff1
*Cassandra我们只使用其底层的存储引擎

应用篇

Nuclear组件介绍

普通节点(Node)
普通节点的职责是接收并处理来自Client的请求,管理该节点上的存储引擎。

中心节点(Seed)
中心节点维护着整个Nuclear集群的拓扑关系(membership),它熟知每一个节点负责的数据区域。它定时对所有节点进行健康检测,因此熟知每一个节点当前的状态及负责的数据区域。

客户端(Nuclear Client)
提供简单有效的CRUD API。详情如下:
Get
@param key<String>
@param dataID<Long>
@param consistencyLevel
@return ByteString

List
@param key<String>
@param Condition<?>
@param consistencyLevel
@return List<ByteString>

Put
@param key<String>
@param dataID<Long>
@param value<ByteString>
@param consistencyLevel

Replace
Put
dataID可选

Delete
@param key<String>
@param dataID<Long>
@param consistencyLevel

NextDataID
@reutrn dataID<Long>

参数详解:
@param dataID<Long> dataID
每一条数据在Nuclear集群中的唯一标示,由系统提供。使用DataID而不是Key作为数据的唯一标示的目的是为了满足Key->List的需求。

@param consistencyLevel
一致性级别,Nuclear系统提供一致性级别选择如下:

  • DISCARD 请求发送至Node后即可,无需认为是否成功(List,Get不支持此级别)
  • MIN 至少成功请求一个Node
  • QUORUM 严格按照N+W>R理论
  • DISCARDQUORUM 按照N+W>R理论,但允许Hinted HandOff
  • ALL成功请求的节点数必须是N@param value<ByteString>
    Nuclear系统存储的数据使用Google的protocol buffers协议,因此存入和取出的数据都是google的 ByteString 类型

    @param Condition
    结构化数据的条件查询参数,目前仅支持MySQL引擎下按DataID检索、排序及分页

    Code Example:
    dddd

    系统部署图
    vvvv

    图释:每一个节点都会和其它的节点建立联系,但来自Client的请求只会落在普通节点上。

    集群管理

    Nuclear提供对节点的增、删、替换操作,面对使用者非常简单,只需要知晓仅有的几个命令即可。
    增加sh node.sh new A
    node.sh是node启动的脚本;new标示当前节点为新增;A标示新增的节点去分担现有的A节点的负载。

    删除delete node A
    进入Nuclear管理后台,执行该命令

    替换sh node.sh replace A

    后台管理: sh manage.sh nodeip nodeport
    目前提供如下功能点:

  • QPS查看
  • Node接收请求总数
  • Node处理请求耗时数据
  • 节点信息查看
  • 集群拓扑信息查看
  • 动态更改节点工作线程数

  • 今天UGC的Nuclear系统介绍到此为止,下回分解 <原理篇> <展望篇>,尽请期待!

    转帖到人人网 分享到人人网

    28 条评论

    1. angelscat 说:

      看不懂 -_-|||

    2. emptyhua 说:

      期待下回分解~

    3. kokko 说:

      看完了,不错的东东,希望有机会可以Open source!

    4. waterye 说:

      高性能:存储引擎:Mysql5.0.45, ???

    5. Jackson 说:

      挺有水平深度的文章··不过有点看不懂饿··

    6. topkey 说:

      看起来确实比较不错。
      学习了

    7. 图明 说:

      很牛逼么?我是门外汉,不懂,不过我是人人网的客户,这几天人人网很烂,几个小游戏都临时更新或者刷不出来,上周服务器还发生bug。具体怎么回事,只有你们自己知道了。现在亮出这些东西有什么意义,一般可悲的家伙。

    8. liancheng 说:

      quorom… 拼错了,是quorum,呵呵

    9. felix021 说:

      书曰:欲先善其事,必先利其器。//是工欲善其事,必先利其器~~

    10. 贾里 说:

      扯那么多有什么意义,如果你能百分之百保证永远并不会被整顿,我就用你。

    11. Sparkle 说:

      我们的需求永远都是全选……

    12. lenghao 说:

      to felix021 liancheng :
      已改,谢谢~ ^_^

    13. lenghao 说:

      to Sparkle:
      悲哀?

    14. lenghao 说:

      to waterye:
      您的意思是 MySQL性能很差?

    15. lenghao 说:

      to kokko
      我们努力中~ 会有开源的一天的~! 谢谢!

    16. XH 说:

      不错不错 淡淡同学挺有才气的 赞一个

    17. dtwa 说:

      仿照得毫无新意 新浪仿得那个在内部都下线开源了 期待你们也开源

    18. 轩轩 说:

      很好很强大,顶!

    19. Jim Jin 说:

      学习中 希望早日开源

    20. shawn 说:

      比较感兴趣最后一张图是用什么软件画的 :) 很漂亮的说

    21. amiao 说:

      想知道实现这个nuclear的过程中最难的部分在哪里,我猜测是:
      1. hinted handoff
      2. NWR,N变化时如何保证NWR仍然存在。如何通知API。
      3. merkle tree的异步同步。
      4. 是否支持snapshot
      5. 多版本问题如何解决的,是否是固定了一个串行点,还是用了时间戳?

    22. lenghao 说:

      to shawn: powerpoint…
      to amiao:
      1. 最难的是merkle tree
      2. snapshot不支持
      3. 简单的版本控制策略上只用了时间戳

    23. forchenyun 说:

      看来人人也在Cassandra上有所尝试啊

    24. huanglaobo 说:

      恩,值得看看。

    25. forchenyun 说:

      很好奇,如果进行结构化查询时,如果查询条件没有你们进行hash的key字段,那你们怎么处理?是所有机器查询完进行merge吗?还是在上层就限制不允许这样的查询?
      谢谢

    26. shanfeng 说:

      还没开源呀,还等 着研究呢.看来还是算了.

    27. lenghao 说:

      to forchenyun
      上层做的限制

    28. 这么好的文章 说:

      水平有限,真是看不懂

    留下回复