2014년 12월 1일 월요일

Spark 사용기 4 - cache() 쓰고 안쓰고 비교

최근에 만든 Spark 위의 Scala M/R 배치는 3개 HDFS File 을 가지고 연산을 수행하는데, 모두 Memory 에 로딩 가능한 정도의 크기이다. 이 경우 RDD 를 Cache 할 필요가 있을까?

그래서 실험을 해 보았다.

(1) Cache 안썻을 때
-> 14초

(2) Cache 썼을 때
-> 1차 시도: 45초
-> 2차 시도: 32초

1차 시도를 했을때 , 45초나 걸려서 다소 놀랐었다. 그때는 뭔가 효율적으로 자료구조를 메모리 DB 화 하기 위해 복잡한 insert 루틴을 수행하고 있나 보다 했었다. 그런데, 그런 논리라고 한다면, 2차 시도때 훨씬 빨라 져야 정상일 것이다.
그런데, 결과는 약간 빨라지긴 했지만, 그다지 안썻을 때에 비해 전혀 개선된 것 같지가 않았다.

(3) cache() 했을 때 값이 남아 있는지 여부?

Shell 콘솔을 껏다 키면, 살짝 간격을 두고 다 없어진다. 그럼 뭔차이일까?
오히려 더 느리기만 하고.... (persist 를 쓰면, keeping 이 되긴 하겠지만...)

일단 짐작을 해 보자면, 클러스터를 Yarn 기반으로 구동 시키면, MR 코드가 Yarn 의 Job 을 수행시켰었다. 이 경우 Cache 를 적절하게 써주면, HDFS 가 아닌 Spark Memory 를 활용하며, 좀더 효율적인 연산을 하지 않을 까 기대했었다...  그 시나리오를 실험해보자, 경미하게 속도 개선이 있었지만, 역시 큰 개선은 없었다. 그러나, Job 성격에 따라 성능 향상이 많은 경우도 있을 것이다. 일단, Cache 는 그런 용도라고 짐작하고 넘어가야겠다.

Yarn 모드가 아닌 Spark Engine 자체로 Master 와 Slave 노드를 설정하고 Memory Instance 를 띄워서 Memory Cluster 를 구동한 경우에는 Memory Cluster 에 로딩 가능한 크기인 경우, 굳이 Cache 를 쓰지 않아도 메모리에서 모든 연산이 이루어지는 듯 하다. 아니, 위 실험 처럼 오히려 속도가 빠르다....
즉, 그러한 환경에서는 ( Stanalone Master & Slave Cluster 모드) Cache 를 쓰지 않는게 더 효율적인듯 하다. 가끔 pinning 할때만, persist 기능을 적절히 써주면 될듯 하다.




ps... persist 를 적절히 쓰면 10배 이상 성능이 개선된다고 한다... 아래 메뉴월 원문을 paste 해본다.  이런실험은 좀더 다양한 M/R 을 짜보고 종합적으로 실험해 보아야 할듯 하다. 일단, 오늘 코딩한 소스로는 아무것도 안쓴게 젤로 빠르다...

RDD Persistence

One of the most important capabilities in Spark is persisting (or caching) a dataset in memory across operations. When you persist an RDD, each node stores any partitions of it that it computes in memory and reuses them in other actions on that dataset (or datasets derived from it). This allows future actions to be much faster (often by more than 10x). Caching is a key tool for iterative algorithms and fast interactive use.
You can mark an RDD to be persisted using the persist() or cache() methods on it. The first time it is computed in an action, it will be kept in memory on the nodes. Spark’s cache is fault-tolerant – if any partition of an RDD is lost, it will automatically be recomputed using the transformations that originally created it.
In addition, each persisted RDD can be stored using a different storage level, allowing you, for example, to persist the dataset on disk, persist it in memory but as serialized Java objects (to save space), replicate it across nodes, or store it off-heap in Tachyon. These levels are set by passing a StorageLevel object (ScalaJavaPython) to persist(). The cache() method is a shorthand for using the default storage level, which isStorageLevel.MEMORY_ONLY (store deserialized objects in memory). The full set of storage levels is:
Storage LevelMeaning
MEMORY_ONLYStore RDD as deserialized Java objects in the JVM. If the RDD does not fit in memory, some partitions will not be cached and will be recomputed on the fly each time they're needed. This is the default level.
MEMORY_AND_DISKStore RDD as deserialized Java objects in the JVM. If the RDD does not fit in memory, store the partitions that don't fit on disk, and read them from there when they're needed.
MEMORY_ONLY_SERStore RDD as serialized Java objects (one byte array per partition). This is generally more space-efficient than deserialized objects, especially when using a fast serializer, but more CPU-intensive to read.
MEMORY_AND_DISK_SERSimilar to MEMORY_ONLY_SER, but spill partitions that don't fit in memory to disk instead of recomputing them on the fly each time they're needed.
DISK_ONLYStore the RDD partitions only on disk.
MEMORY_ONLY_2, MEMORY_AND_DISK_2, etc.Same as the levels above, but replicate each partition on two cluster nodes.
OFF_HEAP (experimental)Store RDD in serialized format in Tachyon. Compared to MEMORY_ONLY_SER, OFF_HEAP reduces garbage collection overhead and allows executors to be smaller and to share a pool of memory, making it attractive in environments with large heaps or multiple concurrent applications. Furthermore, as the RDDs reside in Tachyon, the crash of an executor does not lead to losing the in-memory cache. In this mode, the memory in Tachyon is discardable. Thus, Tachyon does not attempt to reconstruct a block that it evicts from memory.

댓글 없음:

댓글 쓰기