Tôi đang cố gắng hiểu cách bộ nhớ cache của Spark hoạt động.Tìm hiểu về bộ nhớ đệm của Spark
Đây là sự hiểu biết ngây thơ của tôi, xin vui lòng cho tôi biết nếu tôi là thiếu cái gì:
val rdd1 = sc.textFile("some data")
rdd1.cache() //marks rdd1 as cached
val rdd2 = rdd1.filter(...)
val rdd3 = rdd1.map(...)
rdd2.saveAsTextFile("...")
rdd3.saveAsTextFile("...")
Ở phía trên, rdd1 sẽ được nạp từ đĩa (ví dụ HDFS) chỉ một lần. (khi rdd2 được lưu tôi giả định) và sau đó từ bộ nhớ cache (giả sử có đủ RAM) khi rdd3 được lưu)
Bây giờ đây là câu hỏi của tôi. Giả sử tôi muốn cache rdd2 và rdd3 vì chúng sẽ được sử dụng sau này, nhưng tôi không cần rdd1 sau khi tạo chúng.
Về cơ bản có sự trùng lặp, phải không? Kể từ khi rdd2 và rdd3 được tính toán, tôi không cần rdd1 nữa, tôi có lẽ nên unpersist nó, phải không? câu hỏi là khi nào?
Điều này có hiệu quả không? (Tùy chọn A)
val rdd1 = sc.textFile("some data")
rdd1.cache() // marks rdd as cached
val rdd2 = rdd1.filter(...)
val rdd3 = rdd1.map(...)
rdd2.cache()
rdd3.cache()
rdd1.unpersist()
Tia lửa có thêm lời gọi không đáng tin cậy vào DAG không? hoặc là nó được thực hiện ngay lập tức? nếu nó được thực hiện ngay lập tức, sau đó về cơ bản rdd1 sẽ không được lưu trữ khi tôi đọc từ rdd2 và rdd3, phải không?
Tôi có nên thực hiện theo cách này thay thế (Tùy chọn B) không?
val rdd1 = sc.textFile("some data")
rdd1.cache() // marks rdd as cached
val rdd2 = rdd1.filter(...)
val rdd3 = rdd1.map(...)
rdd2.cache()
rdd3.cache()
rdd2.saveAsTextFile("...")
rdd3.saveAsTextFile("...")
rdd1.unpersist()
Vậy câu hỏi là thế này: là lựa chọn A đủ tốt? tức là rdd1
vẫn chỉ tải tệp một lần? Hoặc tôi có cần phải đi với Tùy chọn B không?
Yep, dường như bạn đang ở trên nó. Đây là một chút không may, tôi muốn "cache" có thể đã được chuyển đổi thành một hoạt động DAG và không chỉ thêm RDD ID vào bản đồ ... có rất nhiều trường hợp bạn muốn cache một cái gì đó trung gian, tạo RDD mới, sau đó thả cái cũ. Có lẽ có lý do lý thuyết tốt về lý do tại sao đây không phải là một ý tưởng tốt mặc dù ... trong mọi trường hợp, LRU (tôi giả định) thứ tự của bộ nhớ đệm có nghĩa là cũ chưa sử dụng rdd1 sẽ bị trục xuất nếu rdd2 và rdd3 cần không gian đó cho bộ nhớ đệm ... –
Vì vậy, tôi hầu như chỉ xem xét những gì tồn tại/cache và unpersist đang làm, nhưng vẫn còn chỗ để xem xét Spark đang làm gì khi bạn lấy RDD từ một cái khác và cách nó có thể tối ưu hóa. Tôi không chắc chắn rằng 'rdd1' thậm chí cần phải được lưu trữ, nó có thể được kiểm tra bởi 'rdd2' và' rdd3' khi chúng được lưu trữ hoặc khi DAG được pipelined. Đây là một khu vực màu xám cho tôi mặc dù. – Rich
Đã tiến hành điều tra thêm một chút và truy tìm thông qua trình gỡ lỗi. 'rdd2' và' rdd3' sẽ tham chiếu 'rdd1' làm phụ thuộc. 'rdd1' sẽ tải dữ liệu của nó vào các phân vùng một lần trên hành động đầu tiên được thực hiện. Bây giờ, tại thời điểm này, 'rdd2' và' rdd3' đều áp dụng các biến đổi của chúng cho dữ liệu đã được nạp bởi 'rdd1' trong phân vùng. Tôi tin rằng bộ nhớ đệm cung cấp giá trị nếu bạn chạy nhiều hành động trên cùng một RDD chính xác, nhưng trong trường hợp này các RDD phân nhánh mới, tôi không nghĩ rằng bạn gặp phải vấn đề tương tự vì tôi tin rằng Spark biết rằng 'rdd1' vẫn là phụ thuộc cho 'rdd3' sau lần lưu đầu tiên. – Rich