Spark会立即丢弃短暂的rdds吗?

时间:2016-03-18 14:53:08

标签: python caching apache-spark pyspark rdd

默认情况下,有几个来源将RDD描述为 ephemeral (例如,this s/o answer) - 这意味着除非我们在其上调用cache()或persist(),否则它们不会留在内存中。

因此,假设我们的程序涉及一个短暂的(未由用户显式缓存)RDD,该RDD用于导致RDD实现的一些操作中。 我的问题是:Spark 丢弃物化短暂的RDD 立即 - 或者RDD是否可能留在内存中进行其他操作,即使我们从未要求它被缓存?

另外,如果短暂的RDD留在内存中,是不是因为某些LRU策略尚未将其踢出 - 或者也可能是因为调度优化?

我试图用下面的代码来解决这个问题 - 在4核机器上运行带有python 3.5和spark 1.6.0的Jupyter笔记本 - 但是我会很感激有人知道的答案肯定的。

import pyspark
sc = pyspark.SparkContext()
N = 1000000   # size of dataset
THRESHOLD = 100  # some constant

def f():
    """ do not chache """
    rdd = sc.parallelize(range(N))
    for i in range(10):
        print(rdd.filter(lambda x: x > i * THRESHOLD).count())

def g():
    """ cache """
    rdd = sc.parallelize(range(N)).cache()
    for i in range(10):
        print(rdd.filter(lambda x: x > i * THRESHOLD).count())

对于上面的两个函数,f()不会要求rdd持久化 - 但g()在开头就是这样。当我对两个函数foo()和boo()进行计时时,我得到了两个非常相似的性能,就好像cache()调用没有区别一样。 (事实上​​,使用缓存的那个更慢)。

%%timeit
f()
> 1 loops, best of 3: 2.19 s per loop

%%timeit
g()
> 1 loops, best of 3: 2.7 s per loop

实际上,即使修改f()来调用RDD上的unpersist()也不会改变。

def ff():
    """ modified f() with explicit call to unpersist() """
  rdd = sc.parallelize(range(N))
  for i in range(10):
    rdd.unpersist()
    print(rdd.filter(lambda x: x > i * THRESHOLD).count())

%%timeit
ff()
> 1 loops, best of 3: 2.25 s per loop

unpersist()的文档声明它“将RDD标记为非持久性,并从内存和磁盘中删除[s]所有块。” 这是真的如此 - 或者当Spark知道它将在未来使用RDD时,Spark是否会忽略对unpersist的调用?

1 个答案:

答案 0 :(得分:1)

这里的缓存没有任何价值。从RDD创建range非常便宜(每个分区只需要两个整数才能开始),并且您应用的操作无法从缓存中获益。 persist应用于Java对象而不是Python对象,并且您的代码不会在RDD创建和第一次转换之间执行任何工作。

即使你忽略了所有这一点,这对于使用微小数据来说也是一项非常简单的任务。总成本很可能是由调度和沟通推动的。

如果您想查看缓存操作,请考虑以下示例:

from pyspark import SparkContext
import time

def f(x):
   time.sleep(1)
    return x

sc = SparkContext("local[5]")
rdd = sc.parallelize(range(50), 5).map(f)
rdd.cache()

%time rdd.count()   # First run, no data cached ~10 s
## CPU times: user 16 ms, sys: 4 ms, total: 20 ms
## Wall time: 11.4 s
## 50

%time rdd.count()  # Second time, task results fetched from cache
## CPU times: user 12 ms, sys: 0 ns, total: 12 ms
## Wall time: 114 ms
## 50

rdd.unpersist()  # Data unpersisted

%time rdd.count()  #  Results recomputed ~10s
## CPU times: user 16 ms, sys: 0 ns, total: 16 ms 
## Wall time: 10.1 s
## 50

虽然在这种简单的情况下,持久化行为是可预测的,但一般来说,缓存应被视为提示而不是契约。根据可用资源,任务输出可以保持或不保持,并且可以在没有任何用户干预的情况下从高速缓存中逐出。