同步图运算框架GraphLite(学习手札)基本思想 & 核心API

访问请移步至(David’s Wikipedia) https://www.qingdujun.com/ ,这里有能“击穿”平行宇宙的乱序并行字节流…


本文初步介绍计算所陈世敏老师团队的同步图计算框架——GraphLite。下文以PageRank算法为基础,阐述框架以下两个部分内容,

  • 框架的基本思想
  • 核心API的使用

GraphLite框架源码获取:https://github.com/schencoding/GraphLite
关于框架介绍原文:http://people.apache.org/~edwardyoon/documents/pregel.pdf


目录

分布式存储

GraphLite图计算框架,将图划分为若干个子图,再进行分布式存储、计算。

图->子图->节点

  • 单个机器都没有完整的图;
  • 每个Worker存储着一个子图。而每个子图里又有许多的图节点,这里每个节点都有一个Compute。

节点通信

一个很自然的问题,没有完整的图那么如何完成计算?

这里写图片描述

正是由于图的这种存储模式,使得每个Worker并不需要知道完整的图,只要知道每个计算Compute节点上的数据该往哪里发送就行了。

比如,A节点发现有条边指向的B节点不在本地Worker,那么通过网络连接到B节点即可。
(是否在同一台机器上,已经不重要了,或者说可以做到对Compute是透明的)

同步图计算

那么如何开始计算呢?
这里写图片描述
这里写图片描述

Message

节点可能会收到邻居发来的Message消息,而邻居可能是在另外一个Worker上面。也就是说,超步计算过程中,Worker之间是有通信的。(看上图中的红色圈圈,或者下图中的Data center network图,都很明确的表示了相互之间的通信关系)

Master在扮演Head的同时,一般也会充当Worker的角色。
这里写图片描述

存储结构分析

这里分析一下GraphLite框架的存储结构,大体上为如下模式。其中,Vertex array表示单个Worker中所有图节点数组,Out-edge array表示单个Worker中所有图边数组。(注意这里强调的单个Worker,也就是一台电脑)
这里写图片描述

Input文件中数据格式

4039
88234
0 1
0 2
//…

建立图模型

根据数据格式,再阅读一部分源代码可知,

  • GraphLite框架首先读取了两行文本,先获得了图节点总数、图边总数;
  • 然后一次性申请开辟了所有空间,这就有了Vertex array、Out-edge array;
  • 接来下,通过调用loadGraph开始建立整个子图中节点的关系。

另外,有几点需要注意的,Vertex(图节点)中记录了,

  • 该节点有多少条边;
  • 第一条边的地址在哪里;
  • 同时,每个图节点还挂接了一个指向消息链表(接收邻居发来的信息)的指针。

全局同步器分析

全局同步器就是Aggregator类,该类中维持了两个数据,

AggrValue m_global; /**< aggregator global value of AggrValue type */
AggrValue m_local;  /**< aggregator local value of AggrValue type */

主要的几个API介绍,

accumulateAggr ,统计单个Worker中所有节点的计算结果;(它更改的是m_local的值,在超步过程中会自动发送到Master;Master下发消息时会自动设置m_global值。)
getAggrGlobal ,获取Master下发的上一个超步中的全局计算值;
mutableValue ,修改Vertex图节点值;
sendMessageToAllNeighbors ,给所有邻居发送消息;
voteToHalt ,将本节点置为未激活状态。

小结,

这里写图片描述

PageRank算法

简单介绍一下何为PageRank算法,以及什么情况下就收敛了?
这里写图片描述

相信,依据图的入边情况,大伙已经能看懂上图中的计算式子(左下角)了。

继续分析一下,迭代计算,

  • 首先,每个节点都初始化为1/N;
  • 然后,根据计算式,循环计算每个节点的值;
  • 何时收敛?当上一次计算值,与本次计算值相同时(或者误差在一定范围内)就认为收敛了。

可能的精度丢失

这里涉及到另外一个问题,当图中有上千亿个节点(或者更大)时,N为一个很大的值。那么1/N可能造成存储时精度丢失。陈老师的课件中,提到了将N乘上去,是一个很好的方式。

class VERTEX_CLASS_NAME(): public Vertex <double, double, double> {
public:
    void compute(MessageIterator* pmsgs) {
        double val;
        if (getSuperstep() == 0) {
           val= 1.0;
        } else {
            if (getSuperstep() >= 2) {
                double global_val = * (double *)getAggrGlobal(0);
                if (global_val < EPS) {
                    voteToHalt(); return;
                }
            }

            double sum = 0;
            for ( ; ! pmsgs->done(); pmsgs->next() ) {
                sum += pmsgs->getValue();//此处为Message Value,非Vertex Value,也不是Edge Value。
            }
            val = 0.15 + 0.85 * sum;

            double acc = fabs(getValue() - val);
            accumulateAggr(0, &acc);   //统计单个Worker误差
        }
        * mutableValue() = val;
        const int64_t n = getOutEdgeIterator().size();
        sendMessageToAllNeighbors(val / n);
    }
};

关于aggregator传参,以及更多的功能将在后续的文章中分析。

References:
[1] 陈世敏老师的《大数据管理系统与大规模数据分析》课程讲义
[2]王斌老师的《信息检索导论》课程讲义


©qingdujun
2018-5-15 于北京 怀柔



附录

最后,更多更详细内容,可以参阅陈老师给的资料Aggregator.txt,这里直接附上,

What is Aggregator?

Aggregators are a mechanism for global communication in synchronized graph computation. Aggregators are often used to implement sum, average, max, min, and other types of statistics. An Aggregator can be updated by vertex compute() in parallel. GraphLite guarantees the correctness. That is, all the updates will be correctly reflected in the Aggregator’s global state.

The basic idea is for each worker to keep a local copy of an Aggregator. The local copy is updated by the vertex compute() during a superstep. At the end of a superstep, the workers send their local copies of the Aggregator to the master. The master merges all the local copies and the previous global value to obtain the new global value for the Aggregator. This new global value will be sent back to all the workers, which can be read by vertex compute().

How Master and Workers use AggregatorBase?

  1. Global value and local value
    An Aggregator should have global states and local states.
    We use global value and local value to denote them, respectively.

    The value type is flexible and can be specified as T in the Aggrator.
    The global value is m_global. The local value is m_local.

    Master modifies the global value. Global value is read-only for all the workers.
    A Worker modifies the local value. Master obtains all the workers’ local values and merge them to the global value.

  2. Preparation:
    Both Master and Workers will call Graph::init(). Please see PageRankVertex.cc for an example. This method should use regNumAggr(), regAggr() to register Aggregators with the system.

Master and Workers will use the Aggregator objects from the regAggr() to perform the actual Aggregator computaton.

Master and Workers will call AggregatorBase::getSize() to get the value size of the Aggregator so that the values can be communicated between Master and Workders.
3. In every superstep

  • Master call AggregatorBase::getGlobal() to get the current global value. Then Master sends the global value to all the workers (in the superstep start message).
  • When a worker receives the superstep start message, it extracts the global value, and calls AggregatorBase::setGlobal() to set the (read-only) global value in the local copy of the Aggregator.
  • If vertex compute() calls getAggrGlobal(), then the read-only global value is returned. This value reflects the global value as of the end of the previous superstep.
  • If vertex compute() calls accumulateAggr(), then Worker calls AggregatorBase::accumulate(), which is supposed to accumulate the new value to the local value.
  • At the end of a superstep, every Worker sends an superstep end message including the local value of the Aggregator to Master. Worker calls AggregatorBase::getLocal() to obtain the local value for this purpose.
  • When receiving a superstep end message, Master extracts the embedded local value of the Aggregator and calls AggregatorBase::merge() to merge the local value to the global value.
  1. AggregatorBase::init()
    Master will call AggregatorBase::init() after 3(1). Worker will call AggregatorBase::init() after 3(5).
    AggregatorBase::init() often clears the local value.
    AggregatorBase::init() may or may not clear the global value:
  • Aggregator is cleared at each superstep:
    If this behavior is desired, then clear the global value.
  • Aggregator is accumulated for the entire computation across all
    supersteps:
    If this behavior is desired, then do not clear the global value.
    The global value can be initiated in the class constructor.

The above is the aggregator class in the PageRank example. It implements a sum Aggregator. The value type is double. It is easy to understand the implementation of getGlobal, setGlobal, getLocal. accumulate() adds a new value as given by p to the local value. merge() adds a local value as given by p to the global value.

Here, we clear the global value in init(). So the sum is cleared in each superstep. Note that PageRank uses this Aggregator to compute the difference between the page ranks of two supersteps. So it should be cleared in each super step.

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页